mirror of
https://github.com/minescope/mineping.git
synced 2025-02-25 18:23:28 +03:00
refactor: improve Bedrock error handling and validation
This commit is contained in:
parent
c71236f223
commit
0959403b1b
@ -10,6 +10,7 @@ import crypto from "node:crypto";
|
||||
|
||||
const MAGIC = "00ffff00fefefefefdfdfdfd12345678";
|
||||
const START_TIME = new Date().getTime();
|
||||
const UNCONNECTED_PONG = 0x1c;
|
||||
|
||||
/**
|
||||
* Creates an Unconnected Ping packet.
|
||||
@ -30,12 +31,25 @@ const createUnconnectedPingFrame = (timestamp) => {
|
||||
* Extract Modt from Unconnected Pong Packet and convert to an object
|
||||
* @param {Buffer} unconnectedPongPacket
|
||||
* @returns {Object}
|
||||
* @throws {Error} If packet is malformed or invalid
|
||||
* @see {@link https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Raknet_Protocol#Unconnected_Pong}
|
||||
*/
|
||||
const extractModt = (unconnectedPongPacket) => {
|
||||
// Skip everything to Modt
|
||||
if (
|
||||
!Buffer.isBuffer(unconnectedPongPacket) ||
|
||||
unconnectedPongPacket.length < 35
|
||||
) {
|
||||
throw new Error("Invalid pong packet");
|
||||
}
|
||||
|
||||
const offset = 33;
|
||||
const length = unconnectedPongPacket.readUInt16BE(offset);
|
||||
|
||||
// Check for buffer bounds
|
||||
if (offset + 2 + length > unconnectedPongPacket.length) {
|
||||
throw new Error("Malformed pong packet");
|
||||
}
|
||||
|
||||
let modt = unconnectedPongPacket.toString(
|
||||
"utf-8",
|
||||
offset + 2,
|
||||
@ -43,6 +57,12 @@ const extractModt = (unconnectedPongPacket) => {
|
||||
);
|
||||
|
||||
const components = modt.split(";");
|
||||
|
||||
// Validate required components
|
||||
if (components.length < 9) {
|
||||
throw new Error("Invalid MODT format");
|
||||
}
|
||||
|
||||
const parsedComponents = {
|
||||
edition: components[0],
|
||||
name: components[1],
|
||||
@ -109,20 +129,23 @@ const ping = (host, port = 19132, cb, timeout = 5000) => {
|
||||
}
|
||||
|
||||
socket.on("message", (pongPacket) => {
|
||||
const id = pongPacket[0];
|
||||
if (!Buffer.isBuffer(pongPacket) || pongPacket.length === 0) {
|
||||
handleError(new Error("Invalid packet received"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case 0x1c: {
|
||||
const id = pongPacket[0];
|
||||
if (id !== UNCONNECTED_PONG) {
|
||||
handleError(new Error(`Unexpected packet ID: 0x${id.toString(16)}`));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const modtObject = extractModt(pongPacket);
|
||||
closeSocket();
|
||||
cb(modtObject, null);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
handleError(new Error("Received unexpected packet"));
|
||||
break;
|
||||
}
|
||||
} catch (err) {
|
||||
handleError(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -27,7 +27,7 @@ const varint = {
|
||||
buf.writeUInt8(byte | 0x80, written++);
|
||||
}
|
||||
|
||||
return buf.slice(0, written);
|
||||
return buf.subarray(0, written);
|
||||
},
|
||||
|
||||
/**
|
||||
|
34
types/lib/bedrock.d.ts
vendored
34
types/lib/bedrock.d.ts
vendored
@ -1,10 +1,10 @@
|
||||
/**
|
||||
* @param port The server port.
|
||||
* @param timeout The read/write socket timeout.
|
||||
* @param port The server port (1-65535).
|
||||
* @param timeout The read/write socket timeout in milliseconds.
|
||||
*/
|
||||
export type BedrockPingOptions = {
|
||||
port?: number;
|
||||
timeout?: number;
|
||||
port?: number & { _brand: "Port" }; // 1-65535
|
||||
timeout?: number & { _brand: "Timeout" }; // > 0
|
||||
};
|
||||
|
||||
export type BedrockPingResponse = {
|
||||
@ -26,8 +26,6 @@ export type BedrockPingResponse = {
|
||||
/**
|
||||
* Asynchronously ping Minecraft Bedrock server.
|
||||
*
|
||||
* The optional `options` argument can be an object with a `ping` (default is `19132`) or/and `timeout` (default is `5000`) property.
|
||||
*
|
||||
* @param host The Bedrock server address.
|
||||
* @param options The configuration for pinging Minecraft Bedrock server.
|
||||
*
|
||||
@ -41,13 +39,23 @@ export type BedrockPingResponse = {
|
||||
* The resulting output will resemble:
|
||||
* ```console
|
||||
* {
|
||||
* version: { name: 'Mineplex', protocol: '475' },
|
||||
* players: { max: '5207', online: '5206' },
|
||||
* description: ' New Costumes',
|
||||
* gamemode: 'Survival'
|
||||
* edition: "MCPE",
|
||||
* name: "Mineplex",
|
||||
* version: {
|
||||
* protocolVersion: 475,
|
||||
* minecraftVersion: "1.18.0"
|
||||
* },
|
||||
* players: {
|
||||
* online: 5206,
|
||||
* max: 5207
|
||||
* },
|
||||
* serverId: "12345678",
|
||||
* mapName: "Lobby",
|
||||
* gameMode: "Survival"
|
||||
* }
|
||||
* ```
|
||||
* @see [source](https://github.com/minescope/mineping/blob/915edbec9c9ad811459458600af3531ec0836911/lib/bedrock.js#L204)
|
||||
*/
|
||||
export function pingBedrock(host: string, options?: BedrockPingOptions): Promise<BedrockPingResponse>;
|
||||
|
||||
export function pingBedrock(
|
||||
host: string,
|
||||
options?: BedrockPingOptions
|
||||
): Promise<BedrockPingResponse>;
|
||||
|
Loading…
x
Reference in New Issue
Block a user