@csfloat/cs2-inspect-serializer 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -1
- package/dist/index.d.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +115 -11
- package/dist/index.mjs +112 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CS2 Inspect Link Serializer
|
|
2
2
|
|
|
3
|
-
Lightweight serializer for CS2 inspect links. Fork of the package
|
|
3
|
+
Lightweight serializer and decoder for CS2 inspect links. Fork of the package
|
|
4
4
|
[cs2-inspect-create](https://github.com/candyboyz/cs2-inspect-create).
|
|
5
5
|
|
|
6
6
|
# Installation
|
|
@@ -13,6 +13,26 @@ npm i @csfloat/cs2-inspect-serializer
|
|
|
13
13
|
|
|
14
14
|
See the [tests](tests/gen.test.ts) for examples.
|
|
15
15
|
|
|
16
|
+
```ts
|
|
17
|
+
import { decodeHex, decodeLink, generateHex, generateLink } from "@csfloat/cs2-inspect-serializer";
|
|
18
|
+
|
|
19
|
+
const props = {
|
|
20
|
+
defindex: 7,
|
|
21
|
+
paintindex: 474,
|
|
22
|
+
paintseed: 306,
|
|
23
|
+
paintwear: 0.6336590647697449,
|
|
24
|
+
rarity: 6,
|
|
25
|
+
stickers: [],
|
|
26
|
+
keychains: [],
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const hex = generateHex(props);
|
|
30
|
+
const link = generateLink(props);
|
|
31
|
+
|
|
32
|
+
decodeHex(hex);
|
|
33
|
+
decodeLink(link);
|
|
34
|
+
```
|
|
35
|
+
|
|
16
36
|
# Development
|
|
17
37
|
|
|
18
38
|
```bash
|
package/dist/index.d.mts
CHANGED
|
@@ -149,6 +149,9 @@ interface CEconItemPreviewDataBlock_Sticker {
|
|
|
149
149
|
*/
|
|
150
150
|
declare const CEconItemPreviewDataBlock_Sticker: CEconItemPreviewDataBlock_Sticker$Type;
|
|
151
151
|
|
|
152
|
+
declare const decodeHex: (hex: string) => CEconItemPreviewDataBlock;
|
|
153
|
+
declare const decodeLink: (link: string) => CEconItemPreviewDataBlock;
|
|
154
|
+
|
|
152
155
|
declare const previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
|
|
153
156
|
/**
|
|
154
157
|
* Creates the hex representation of the inspect data
|
|
@@ -163,4 +166,4 @@ declare const generateHex: ({ paintwear, ...props }: CEconItemPreviewDataBlock)
|
|
|
163
166
|
*/
|
|
164
167
|
declare const generateLink: (props: CEconItemPreviewDataBlock) => string;
|
|
165
168
|
|
|
166
|
-
export { generateHex, generateLink, previewLink };
|
|
169
|
+
export { CEconItemPreviewDataBlock, decodeHex, decodeLink, generateHex, generateLink, previewLink };
|
package/dist/index.d.ts
CHANGED
|
@@ -149,6 +149,9 @@ interface CEconItemPreviewDataBlock_Sticker {
|
|
|
149
149
|
*/
|
|
150
150
|
declare const CEconItemPreviewDataBlock_Sticker: CEconItemPreviewDataBlock_Sticker$Type;
|
|
151
151
|
|
|
152
|
+
declare const decodeHex: (hex: string) => CEconItemPreviewDataBlock;
|
|
153
|
+
declare const decodeLink: (link: string) => CEconItemPreviewDataBlock;
|
|
154
|
+
|
|
152
155
|
declare const previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
|
|
153
156
|
/**
|
|
154
157
|
* Creates the hex representation of the inspect data
|
|
@@ -163,4 +166,4 @@ declare const generateHex: ({ paintwear, ...props }: CEconItemPreviewDataBlock)
|
|
|
163
166
|
*/
|
|
164
167
|
declare const generateLink: (props: CEconItemPreviewDataBlock) => string;
|
|
165
168
|
|
|
166
|
-
export { generateHex, generateLink, previewLink };
|
|
169
|
+
export { CEconItemPreviewDataBlock, decodeHex, decodeLink, generateHex, generateLink, previewLink };
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
CEconItemPreviewDataBlock: () => CEconItemPreviewDataBlock,
|
|
34
|
+
decodeHex: () => decodeHex,
|
|
35
|
+
decodeLink: () => decodeLink,
|
|
33
36
|
generateHex: () => generateHex,
|
|
34
37
|
generateLink: () => generateLink,
|
|
35
38
|
previewLink: () => previewLink
|
|
@@ -289,27 +292,125 @@ var CEconItemPreviewDataBlock_Sticker$Type = class extends import_runtime.Messag
|
|
|
289
292
|
var CEconItemPreviewDataBlock_Sticker = new CEconItemPreviewDataBlock_Sticker$Type();
|
|
290
293
|
|
|
291
294
|
// src/index.ts
|
|
295
|
+
var import_buffer3 = require("buffer");
|
|
296
|
+
|
|
297
|
+
// src/decode.ts
|
|
298
|
+
var import_buffer2 = require("buffer");
|
|
299
|
+
|
|
300
|
+
// src/inspect-payload.ts
|
|
292
301
|
var import_crc_32 = __toESM(require("crc-32"));
|
|
293
302
|
var import_buffer = require("buffer");
|
|
294
|
-
var previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
|
|
295
303
|
var floatToBytes = (floatValue) => {
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
return
|
|
304
|
+
const buffer = new ArrayBuffer(4);
|
|
305
|
+
const view = new DataView(buffer);
|
|
306
|
+
view.setFloat32(0, floatValue, true);
|
|
307
|
+
return view.getUint32(0, true);
|
|
308
|
+
};
|
|
309
|
+
var bytesToFloat = (uintValue) => {
|
|
310
|
+
const buffer = new ArrayBuffer(4);
|
|
311
|
+
const view = new DataView(buffer);
|
|
312
|
+
view.setUint32(0, uintValue, true);
|
|
313
|
+
return view.getFloat32(0, true);
|
|
314
|
+
};
|
|
315
|
+
var getChecksum = (payload) => {
|
|
316
|
+
const bufferPayload = import_buffer.Buffer.concat([Uint8Array.from([0]), payload]);
|
|
317
|
+
const crc = import_crc_32.default.buf(bufferPayload);
|
|
318
|
+
const x_crc = crc & 65535 ^ payload.byteLength * crc;
|
|
319
|
+
return (x_crc & 4294967295) >>> 0;
|
|
300
320
|
};
|
|
321
|
+
|
|
322
|
+
// src/decode.ts
|
|
323
|
+
var normalizeDecodedEcon = (econ) => {
|
|
324
|
+
return {
|
|
325
|
+
...econ,
|
|
326
|
+
paintwear: econ.paintwear === void 0 ? void 0 : bytesToFloat(econ.paintwear)
|
|
327
|
+
};
|
|
328
|
+
};
|
|
329
|
+
var hasDecodedInspectPayload = (econ) => {
|
|
330
|
+
return econ.itemid !== void 0 || econ.defindex !== void 0 || econ.paintindex !== void 0 || econ.paintseed !== void 0 || econ.stickers.length > 0 || econ.keychains.length > 0;
|
|
331
|
+
};
|
|
332
|
+
var assertValidHex = (hex) => {
|
|
333
|
+
if (!/^[0-9A-F]+$/i.test(hex) || hex.length % 2 !== 0) {
|
|
334
|
+
throw new Error("Invalid inspect hex payload");
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
var decodeURIComponentSafely = (value) => {
|
|
338
|
+
try {
|
|
339
|
+
return decodeURIComponent(value);
|
|
340
|
+
} catch {
|
|
341
|
+
return value;
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
var extractHexFromLink = (link) => {
|
|
345
|
+
const decodedLink = decodeURIComponentSafely(link.trim());
|
|
346
|
+
const linkMatch = decodedLink.match(
|
|
347
|
+
/^(?:steam:\/\/(?:run|rungame)\/730\/(?:76561202255233023\/)?\/?)?\+?csgo_econ_action_preview\s+([0-9A-F]+)$/i
|
|
348
|
+
);
|
|
349
|
+
if (linkMatch?.[1]) {
|
|
350
|
+
assertValidHex(linkMatch[1]);
|
|
351
|
+
return linkMatch[1];
|
|
352
|
+
}
|
|
353
|
+
throw new Error("Invalid inspect link");
|
|
354
|
+
};
|
|
355
|
+
var decodePayload = (payload, isValidPayload) => {
|
|
356
|
+
const econ = normalizeDecodedEcon(CEconItemPreviewDataBlock.fromBinary(payload));
|
|
357
|
+
if (!isValidPayload(econ)) {
|
|
358
|
+
throw new Error("Invalid inspect hex payload");
|
|
359
|
+
}
|
|
360
|
+
return econ;
|
|
361
|
+
};
|
|
362
|
+
var decodeWrappedBuffer = (buffer) => {
|
|
363
|
+
if (buffer.length < 5 || buffer[0] !== 0) {
|
|
364
|
+
throw new Error("Invalid inspect hex payload");
|
|
365
|
+
}
|
|
366
|
+
const payload = buffer.subarray(1, -4);
|
|
367
|
+
const expectedChecksum = buffer.readUInt32BE(buffer.length - 4);
|
|
368
|
+
const actualChecksum = getChecksum(payload);
|
|
369
|
+
if (expectedChecksum !== actualChecksum) {
|
|
370
|
+
throw new Error("Inspect hex checksum mismatch");
|
|
371
|
+
}
|
|
372
|
+
return decodePayload(payload, hasDecodedInspectPayload);
|
|
373
|
+
};
|
|
374
|
+
var isDecodedMaskedInspectPayload = (econ) => {
|
|
375
|
+
return econ.itemid !== void 0 && econ.defindex !== void 0 && econ.paintindex !== void 0 && econ.inventory !== void 0 && econ.origin !== void 0;
|
|
376
|
+
};
|
|
377
|
+
var decodeMaskedBuffer = (buffer) => {
|
|
378
|
+
if (buffer.length < 5) {
|
|
379
|
+
throw new Error("Invalid inspect hex payload");
|
|
380
|
+
}
|
|
381
|
+
const unmaskedBuffer = xorMaskBuffer(buffer, buffer[0]);
|
|
382
|
+
if (unmaskedBuffer[0] !== 0) {
|
|
383
|
+
throw new Error("Invalid inspect hex payload");
|
|
384
|
+
}
|
|
385
|
+
return decodePayload(unmaskedBuffer.subarray(1, -4), isDecodedMaskedInspectPayload);
|
|
386
|
+
};
|
|
387
|
+
var xorMaskBuffer = (buffer, key) => {
|
|
388
|
+
return import_buffer2.Buffer.from(buffer.map((byte) => byte ^ key));
|
|
389
|
+
};
|
|
390
|
+
var decodeHex = (hex) => {
|
|
391
|
+
const normalizedHex = hex.trim();
|
|
392
|
+
assertValidHex(normalizedHex);
|
|
393
|
+
const buffer = import_buffer2.Buffer.from(normalizedHex, "hex");
|
|
394
|
+
if (buffer[0] === 0) {
|
|
395
|
+
return decodeWrappedBuffer(buffer);
|
|
396
|
+
}
|
|
397
|
+
return decodeMaskedBuffer(buffer);
|
|
398
|
+
};
|
|
399
|
+
var decodeLink = (link) => {
|
|
400
|
+
return decodeHex(extractHexFromLink(link));
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// src/index.ts
|
|
404
|
+
var previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
|
|
301
405
|
var generateHex = ({ paintwear = 1e-3, ...props }) => {
|
|
302
406
|
const econ = {
|
|
303
407
|
...props,
|
|
304
408
|
paintwear: floatToBytes(paintwear)
|
|
305
409
|
};
|
|
306
410
|
const payload = CEconItemPreviewDataBlock.toBinary(econ);
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const crcBuffer = import_buffer.Buffer.alloc(4);
|
|
311
|
-
crcBuffer.writeUInt32BE((x_crc & 4294967295) >>> 0, 0);
|
|
312
|
-
return import_buffer.Buffer.concat([bufferPayload, crcBuffer]).toString("hex").toUpperCase();
|
|
411
|
+
const crcBuffer = import_buffer3.Buffer.alloc(4);
|
|
412
|
+
crcBuffer.writeUInt32BE(getChecksum(payload), 0);
|
|
413
|
+
return import_buffer3.Buffer.concat([Uint8Array.from([0]), payload, crcBuffer]).toString("hex").toUpperCase();
|
|
313
414
|
};
|
|
314
415
|
var generateLink = (props) => {
|
|
315
416
|
const hex = generateHex(props);
|
|
@@ -317,6 +418,9 @@ var generateLink = (props) => {
|
|
|
317
418
|
};
|
|
318
419
|
// Annotate the CommonJS export names for ESM import in node:
|
|
319
420
|
0 && (module.exports = {
|
|
421
|
+
CEconItemPreviewDataBlock,
|
|
422
|
+
decodeHex,
|
|
423
|
+
decodeLink,
|
|
320
424
|
generateHex,
|
|
321
425
|
generateLink,
|
|
322
426
|
previewLink
|
package/dist/index.mjs
CHANGED
|
@@ -251,33 +251,134 @@ var CEconItemPreviewDataBlock_Sticker$Type = class extends MessageType {
|
|
|
251
251
|
var CEconItemPreviewDataBlock_Sticker = new CEconItemPreviewDataBlock_Sticker$Type();
|
|
252
252
|
|
|
253
253
|
// src/index.ts
|
|
254
|
+
import { Buffer as Buffer3 } from "buffer";
|
|
255
|
+
|
|
256
|
+
// src/decode.ts
|
|
257
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
258
|
+
|
|
259
|
+
// src/inspect-payload.ts
|
|
254
260
|
import CRC32 from "crc-32";
|
|
255
261
|
import { Buffer } from "buffer";
|
|
256
|
-
var previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
|
|
257
262
|
var floatToBytes = (floatValue) => {
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
return
|
|
263
|
+
const buffer = new ArrayBuffer(4);
|
|
264
|
+
const view = new DataView(buffer);
|
|
265
|
+
view.setFloat32(0, floatValue, true);
|
|
266
|
+
return view.getUint32(0, true);
|
|
267
|
+
};
|
|
268
|
+
var bytesToFloat = (uintValue) => {
|
|
269
|
+
const buffer = new ArrayBuffer(4);
|
|
270
|
+
const view = new DataView(buffer);
|
|
271
|
+
view.setUint32(0, uintValue, true);
|
|
272
|
+
return view.getFloat32(0, true);
|
|
273
|
+
};
|
|
274
|
+
var getChecksum = (payload) => {
|
|
275
|
+
const bufferPayload = Buffer.concat([Uint8Array.from([0]), payload]);
|
|
276
|
+
const crc = CRC32.buf(bufferPayload);
|
|
277
|
+
const x_crc = crc & 65535 ^ payload.byteLength * crc;
|
|
278
|
+
return (x_crc & 4294967295) >>> 0;
|
|
262
279
|
};
|
|
280
|
+
|
|
281
|
+
// src/decode.ts
|
|
282
|
+
var normalizeDecodedEcon = (econ) => {
|
|
283
|
+
return {
|
|
284
|
+
...econ,
|
|
285
|
+
paintwear: econ.paintwear === void 0 ? void 0 : bytesToFloat(econ.paintwear)
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
var hasDecodedInspectPayload = (econ) => {
|
|
289
|
+
return econ.itemid !== void 0 || econ.defindex !== void 0 || econ.paintindex !== void 0 || econ.paintseed !== void 0 || econ.stickers.length > 0 || econ.keychains.length > 0;
|
|
290
|
+
};
|
|
291
|
+
var assertValidHex = (hex) => {
|
|
292
|
+
if (!/^[0-9A-F]+$/i.test(hex) || hex.length % 2 !== 0) {
|
|
293
|
+
throw new Error("Invalid inspect hex payload");
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
var decodeURIComponentSafely = (value) => {
|
|
297
|
+
try {
|
|
298
|
+
return decodeURIComponent(value);
|
|
299
|
+
} catch {
|
|
300
|
+
return value;
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
var extractHexFromLink = (link) => {
|
|
304
|
+
const decodedLink = decodeURIComponentSafely(link.trim());
|
|
305
|
+
const linkMatch = decodedLink.match(
|
|
306
|
+
/^(?:steam:\/\/(?:run|rungame)\/730\/(?:76561202255233023\/)?\/?)?\+?csgo_econ_action_preview\s+([0-9A-F]+)$/i
|
|
307
|
+
);
|
|
308
|
+
if (linkMatch?.[1]) {
|
|
309
|
+
assertValidHex(linkMatch[1]);
|
|
310
|
+
return linkMatch[1];
|
|
311
|
+
}
|
|
312
|
+
throw new Error("Invalid inspect link");
|
|
313
|
+
};
|
|
314
|
+
var decodePayload = (payload, isValidPayload) => {
|
|
315
|
+
const econ = normalizeDecodedEcon(CEconItemPreviewDataBlock.fromBinary(payload));
|
|
316
|
+
if (!isValidPayload(econ)) {
|
|
317
|
+
throw new Error("Invalid inspect hex payload");
|
|
318
|
+
}
|
|
319
|
+
return econ;
|
|
320
|
+
};
|
|
321
|
+
var decodeWrappedBuffer = (buffer) => {
|
|
322
|
+
if (buffer.length < 5 || buffer[0] !== 0) {
|
|
323
|
+
throw new Error("Invalid inspect hex payload");
|
|
324
|
+
}
|
|
325
|
+
const payload = buffer.subarray(1, -4);
|
|
326
|
+
const expectedChecksum = buffer.readUInt32BE(buffer.length - 4);
|
|
327
|
+
const actualChecksum = getChecksum(payload);
|
|
328
|
+
if (expectedChecksum !== actualChecksum) {
|
|
329
|
+
throw new Error("Inspect hex checksum mismatch");
|
|
330
|
+
}
|
|
331
|
+
return decodePayload(payload, hasDecodedInspectPayload);
|
|
332
|
+
};
|
|
333
|
+
var isDecodedMaskedInspectPayload = (econ) => {
|
|
334
|
+
return econ.itemid !== void 0 && econ.defindex !== void 0 && econ.paintindex !== void 0 && econ.inventory !== void 0 && econ.origin !== void 0;
|
|
335
|
+
};
|
|
336
|
+
var decodeMaskedBuffer = (buffer) => {
|
|
337
|
+
if (buffer.length < 5) {
|
|
338
|
+
throw new Error("Invalid inspect hex payload");
|
|
339
|
+
}
|
|
340
|
+
const unmaskedBuffer = xorMaskBuffer(buffer, buffer[0]);
|
|
341
|
+
if (unmaskedBuffer[0] !== 0) {
|
|
342
|
+
throw new Error("Invalid inspect hex payload");
|
|
343
|
+
}
|
|
344
|
+
return decodePayload(unmaskedBuffer.subarray(1, -4), isDecodedMaskedInspectPayload);
|
|
345
|
+
};
|
|
346
|
+
var xorMaskBuffer = (buffer, key) => {
|
|
347
|
+
return Buffer2.from(buffer.map((byte) => byte ^ key));
|
|
348
|
+
};
|
|
349
|
+
var decodeHex = (hex) => {
|
|
350
|
+
const normalizedHex = hex.trim();
|
|
351
|
+
assertValidHex(normalizedHex);
|
|
352
|
+
const buffer = Buffer2.from(normalizedHex, "hex");
|
|
353
|
+
if (buffer[0] === 0) {
|
|
354
|
+
return decodeWrappedBuffer(buffer);
|
|
355
|
+
}
|
|
356
|
+
return decodeMaskedBuffer(buffer);
|
|
357
|
+
};
|
|
358
|
+
var decodeLink = (link) => {
|
|
359
|
+
return decodeHex(extractHexFromLink(link));
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
// src/index.ts
|
|
363
|
+
var previewLink = "steam://rungame/730/76561202255233023/+csgo_econ_action_preview";
|
|
263
364
|
var generateHex = ({ paintwear = 1e-3, ...props }) => {
|
|
264
365
|
const econ = {
|
|
265
366
|
...props,
|
|
266
367
|
paintwear: floatToBytes(paintwear)
|
|
267
368
|
};
|
|
268
369
|
const payload = CEconItemPreviewDataBlock.toBinary(econ);
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const crcBuffer = Buffer.alloc(4);
|
|
273
|
-
crcBuffer.writeUInt32BE((x_crc & 4294967295) >>> 0, 0);
|
|
274
|
-
return Buffer.concat([bufferPayload, crcBuffer]).toString("hex").toUpperCase();
|
|
370
|
+
const crcBuffer = Buffer3.alloc(4);
|
|
371
|
+
crcBuffer.writeUInt32BE(getChecksum(payload), 0);
|
|
372
|
+
return Buffer3.concat([Uint8Array.from([0]), payload, crcBuffer]).toString("hex").toUpperCase();
|
|
275
373
|
};
|
|
276
374
|
var generateLink = (props) => {
|
|
277
375
|
const hex = generateHex(props);
|
|
278
376
|
return `${previewLink} ${hex}`;
|
|
279
377
|
};
|
|
280
378
|
export {
|
|
379
|
+
CEconItemPreviewDataBlock,
|
|
380
|
+
decodeHex,
|
|
381
|
+
decodeLink,
|
|
281
382
|
generateHex,
|
|
282
383
|
generateLink,
|
|
283
384
|
previewLink
|