Skip to content

Commit eefe58b

Browse files
authored
Merge pull request #9 from Daniel-Ric/feature/2026-01-28/analyze-and-fix-empty-top-creators-response
fix-mc-creators
2 parents f495cb8 + 7dea0cd commit eefe58b

File tree

3 files changed

+73
-13
lines changed

3 files changed

+73
-13
lines changed

src/routes/inventory.routes.js

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import express from "express";
22
import Joi from "joi";
3-
import jwtLib from "jsonwebtoken";
43
import {jwtMiddleware} from "../utils/jwt.js";
54
import {asyncHandler} from "../utils/async.js";
65
import {getEntityToken, getPlayFabInventory, loginWithXbox} from "../services/playfab.service.js";
7-
import {getMCBalances, getMCInventory} from "../services/minecraft.service.js";
6+
import {extractReceiptEntitlements, getMCBalances, getMCInventory} from "../services/minecraft.service.js";
87
import {badRequest} from "../utils/httpError.js";
98

109
const router = express.Router();
@@ -236,21 +235,17 @@ router.get("/minecraft/creators/top", jwtMiddleware, asyncHandler(async (req, re
236235

237236
const counts = {};
238237
for (const e of (ents || [])) {
239-
const rawReceipt = e?.Receipt ?? e?.receipt ?? null;
240-
if (typeof rawReceipt !== "string" || !rawReceipt) continue;
241-
242-
let decoded;
243-
try {
244-
decoded = jwtLib.decode(rawReceipt);
245-
} catch {
238+
const directCreator = e?.creatorId ?? e?.CreatorId ?? e?.creatorID ?? null;
239+
if (directCreator) {
240+
counts[directCreator] = (counts[directCreator] || 0) + 1;
246241
continue;
247242
}
248-
249-
const recEnts = decoded?.Receipt?.Entitlements;
243+
const rawReceipt = e?.Receipt ?? e?.receipt ?? null;
244+
const recEnts = extractReceiptEntitlements(rawReceipt);
250245
if (!Array.isArray(recEnts)) continue;
251246

252247
for (const re of recEnts) {
253-
const cid = re?.CreatorId ?? re?.creatorId ?? null;
248+
const cid = re?.CreatorId ?? re?.creatorId ?? re?.creatorID ?? null;
254249
if (!cid) continue;
255250
counts[cid] = (counts[cid] || 0) + 1;
256251
}

src/services/minecraft.service.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {randomUUID} from "crypto";
2+
import jwtLib from "jsonwebtoken";
23

34
import {env} from "../config/env.js";
45
import {badRequest, forbidden, internal, unauthorized} from "../utils/httpError.js";
@@ -91,6 +92,43 @@ export async function getMCInventory(mcToken, includeReceipt = false) {
9192
}
9293
}
9394

95+
export function extractReceiptEntitlements(rawReceipt) {
96+
if (!rawReceipt) return null;
97+
if (typeof rawReceipt === "string") {
98+
const trimmed = rawReceipt.trim();
99+
if (!trimmed) return null;
100+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
101+
try {
102+
const parsed = JSON.parse(trimmed);
103+
return parsed?.Receipt?.Entitlements || parsed?.receipt?.entitlements || parsed?.entitlements || null;
104+
} catch {
105+
return null;
106+
}
107+
}
108+
let decoded = null;
109+
try {
110+
decoded = jwtLib.decode(trimmed);
111+
} catch {
112+
decoded = null;
113+
}
114+
const decodedEnts = decoded?.Receipt?.Entitlements || decoded?.receipt?.entitlements || decoded?.entitlements || null;
115+
if (Array.isArray(decodedEnts)) return decodedEnts;
116+
if (!trimmed.includes(".")) {
117+
try {
118+
const parsed = JSON.parse(Buffer.from(trimmed, "base64").toString("utf8"));
119+
return parsed?.Receipt?.Entitlements || parsed?.receipt?.entitlements || parsed?.entitlements || null;
120+
} catch {
121+
return null;
122+
}
123+
}
124+
return null;
125+
}
126+
if (typeof rawReceipt === "object") {
127+
return rawReceipt?.Receipt?.Entitlements || rawReceipt?.receipt?.entitlements || rawReceipt?.entitlements || null;
128+
}
129+
return null;
130+
}
131+
94132
export async function getMCBalances(mcToken) {
95133
if (!mcToken) throw badRequest("mcToken missing");
96134
try {

tests/messaging.test.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import test from "node:test";
22
import assert from "node:assert/strict";
33

4-
import {buildMarketplaceMessageEventsPayload, buildMarketplaceMessagingPayload} from "../src/services/minecraft.service.js";
4+
import jwtLib from "jsonwebtoken";
5+
import {buildMarketplaceMessageEventsPayload, buildMarketplaceMessagingPayload, extractReceiptEntitlements} from "../src/services/minecraft.service.js";
56

67
test("buildMarketplaceMessagingPayload uses defaults", () => {
78
const {payload, sessionId} = buildMarketplaceMessagingPayload({});
@@ -72,3 +73,29 @@ test("buildMarketplaceMessageEventsPayload builds multiple events", () => {
7273
eventDateTime: "2026-01-21T10:14:44.051Z"
7374
}]);
7475
});
76+
77+
test("extractReceiptEntitlements reads jwt receipt entitlements", () => {
78+
const receiptPayload = {Receipt: {Entitlements: [{CreatorId: "creator-1"}]}};
79+
const token = jwtLib.sign(receiptPayload, "secret");
80+
const ents = extractReceiptEntitlements(token);
81+
assert.deepEqual(ents, receiptPayload.Receipt.Entitlements);
82+
});
83+
84+
test("extractReceiptEntitlements reads json receipt entitlements", () => {
85+
const receiptPayload = {Receipt: {Entitlements: [{CreatorId: "creator-2"}]}};
86+
const ents = extractReceiptEntitlements(JSON.stringify(receiptPayload));
87+
assert.deepEqual(ents, receiptPayload.Receipt.Entitlements);
88+
});
89+
90+
test("extractReceiptEntitlements reads base64 receipt entitlements", () => {
91+
const receiptPayload = {Receipt: {Entitlements: [{CreatorId: "creator-3"}]}};
92+
const encoded = Buffer.from(JSON.stringify(receiptPayload), "utf8").toString("base64");
93+
const ents = extractReceiptEntitlements(encoded);
94+
assert.deepEqual(ents, receiptPayload.Receipt.Entitlements);
95+
});
96+
97+
test("extractReceiptEntitlements reads object receipt entitlements", () => {
98+
const receiptPayload = {Receipt: {Entitlements: [{CreatorId: "creator-4"}]}};
99+
const ents = extractReceiptEntitlements(receiptPayload);
100+
assert.deepEqual(ents, receiptPayload.Receipt.Entitlements);
101+
});

0 commit comments

Comments
 (0)