Skip to content

Commit 1558fc6

Browse files
authored
Merge pull request #10 from Daniel-Ric/feature/2026-01-28/analyze-and-fix-empty-top-creators-response
receipt-payload
2 parents eefe58b + 34f6a78 commit 1558fc6

File tree

2 files changed

+69
-14
lines changed

2 files changed

+69
-14
lines changed

src/services/minecraft.service.js

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,34 +97,68 @@ export function extractReceiptEntitlements(rawReceipt) {
9797
if (typeof rawReceipt === "string") {
9898
const trimmed = rawReceipt.trim();
9999
if (!trimmed) return null;
100-
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
100+
const normalized = trimmed.replace(/^(bearer|jwt)\s+/i, "");
101+
if (!normalized) return null;
102+
if (normalized.startsWith("{") || normalized.startsWith("[")) {
101103
try {
102-
const parsed = JSON.parse(trimmed);
104+
const parsed = JSON.parse(normalized);
103105
return parsed?.Receipt?.Entitlements || parsed?.receipt?.entitlements || parsed?.entitlements || null;
104106
} catch {
105107
return null;
106108
}
107109
}
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;
110+
const decoded = jwtLib.decode(normalized, {complete: true, json: true});
111+
const payload = decoded?.payload || decoded;
112+
const decodedEnts = payload?.Receipt?.Entitlements || payload?.Receipt?.entitlements || payload?.receipt?.entitlements || payload?.Entitlements || payload?.entitlements || null;
115113
if (Array.isArray(decodedEnts)) return decodedEnts;
116-
if (!trimmed.includes(".")) {
114+
const receiptValue = payload?.Receipt ?? payload?.receipt ?? null;
115+
if (typeof receiptValue === "string") {
117116
try {
118-
const parsed = JSON.parse(Buffer.from(trimmed, "base64").toString("utf8"));
119-
return parsed?.Receipt?.Entitlements || parsed?.receipt?.entitlements || parsed?.entitlements || null;
117+
const parsed = JSON.parse(receiptValue);
118+
return parsed?.Receipt?.Entitlements || parsed?.Receipt?.entitlements || parsed?.receipt?.entitlements || parsed?.Entitlements || parsed?.entitlements || null;
119+
} catch {
120+
return null;
121+
}
122+
}
123+
if (typeof payload === "string") {
124+
try {
125+
const parsed = JSON.parse(payload);
126+
return parsed?.Receipt?.Entitlements || parsed?.Receipt?.entitlements || parsed?.receipt?.entitlements || parsed?.Entitlements || parsed?.entitlements || null;
127+
} catch {
128+
return null;
129+
}
130+
}
131+
const parts = normalized.split(".");
132+
if (parts.length >= 2) {
133+
const payloadPart = parts[1];
134+
const base64Payload = payloadPart.replace(/-/g, "+").replace(/_/g, "/");
135+
const padLength = base64Payload.length % 4;
136+
const padded = padLength ? base64Payload.padEnd(base64Payload.length + (4 - padLength), "=") : base64Payload;
137+
try {
138+
const parsed = JSON.parse(Buffer.from(padded, "base64").toString("utf8"));
139+
return parsed?.Receipt?.Entitlements || parsed?.Receipt?.entitlements || parsed?.receipt?.entitlements || parsed?.Entitlements || parsed?.entitlements || null;
140+
} catch {
141+
return null;
142+
}
143+
}
144+
if (!normalized.includes(".")) {
145+
try {
146+
const parsed = JSON.parse(Buffer.from(normalized, "base64").toString("utf8"));
147+
return parsed?.Receipt?.Entitlements || parsed?.Receipt?.entitlements || parsed?.receipt?.entitlements || parsed?.Entitlements || parsed?.entitlements || null;
120148
} catch {
121149
return null;
122150
}
123151
}
124152
return null;
125153
}
126154
if (typeof rawReceipt === "object") {
127-
return rawReceipt?.Receipt?.Entitlements || rawReceipt?.receipt?.entitlements || rawReceipt?.entitlements || null;
155+
const direct = rawReceipt?.Receipt?.Entitlements || rawReceipt?.Receipt?.entitlements || rawReceipt?.receipt?.entitlements || rawReceipt?.Entitlements || rawReceipt?.entitlements || null;
156+
if (Array.isArray(direct)) return direct;
157+
const nested = rawReceipt?.Receipt ?? rawReceipt?.receipt ?? null;
158+
if (nested && nested !== rawReceipt) {
159+
return extractReceiptEntitlements(nested);
160+
}
161+
return null;
128162
}
129163
return null;
130164
}

tests/messaging.test.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,20 @@ test("extractReceiptEntitlements reads jwt receipt entitlements", () => {
8181
assert.deepEqual(ents, receiptPayload.Receipt.Entitlements);
8282
});
8383

84+
test("extractReceiptEntitlements reads jwt with prefix", () => {
85+
const receiptPayload = {Receipt: {Entitlements: [{CreatorId: "creator-1b"}]}};
86+
const token = jwtLib.sign(receiptPayload, "secret");
87+
const ents = extractReceiptEntitlements(`Bearer ${token}`);
88+
assert.deepEqual(ents, receiptPayload.Receipt.Entitlements);
89+
});
90+
91+
test("extractReceiptEntitlements reads jwt with string receipt payload", () => {
92+
const receiptPayload = {Entitlements: [{CreatorId: "creator-1c"}]};
93+
const token = jwtLib.sign({Receipt: JSON.stringify(receiptPayload)}, "secret");
94+
const ents = extractReceiptEntitlements(token);
95+
assert.deepEqual(ents, receiptPayload.Entitlements);
96+
});
97+
8498
test("extractReceiptEntitlements reads json receipt entitlements", () => {
8599
const receiptPayload = {Receipt: {Entitlements: [{CreatorId: "creator-2"}]}};
86100
const ents = extractReceiptEntitlements(JSON.stringify(receiptPayload));
@@ -89,7 +103,7 @@ test("extractReceiptEntitlements reads json receipt entitlements", () => {
89103

90104
test("extractReceiptEntitlements reads base64 receipt entitlements", () => {
91105
const receiptPayload = {Receipt: {Entitlements: [{CreatorId: "creator-3"}]}};
92-
const encoded = Buffer.from(JSON.stringify(receiptPayload), "utf8").toString("base64");
106+
const encoded = Buffer.from(JSON.stringify(receiptPayload), "utf8").toString("base64").replace(/=+$/, "");
93107
const ents = extractReceiptEntitlements(encoded);
94108
assert.deepEqual(ents, receiptPayload.Receipt.Entitlements);
95109
});
@@ -99,3 +113,10 @@ test("extractReceiptEntitlements reads object receipt entitlements", () => {
99113
const ents = extractReceiptEntitlements(receiptPayload);
100114
assert.deepEqual(ents, receiptPayload.Receipt.Entitlements);
101115
});
116+
117+
test("extractReceiptEntitlements reads nested receipt strings", () => {
118+
const receiptPayload = {Receipt: {Entitlements: [{CreatorId: "creator-5"}]}};
119+
const token = jwtLib.sign(receiptPayload, "secret");
120+
const ents = extractReceiptEntitlements({receipt: token});
121+
assert.deepEqual(ents, receiptPayload.Receipt.Entitlements);
122+
});

0 commit comments

Comments
 (0)