minecraft-protocol
Version:
Parse and serialize minecraft packets, plus authentication and encryption.
307 lines (280 loc) • 10.6 kB
TypeScript
/// <reference types="node" />
import { EventEmitter } from 'events';
import { Socket } from 'net'
import * as Stream from 'stream'
import { Agent } from 'http'
import { Transform } from "readable-stream";
import { BinaryLike, KeyObject } from 'crypto';
import { Realm } from "prismarine-realms"
import NodeRSA from 'node-rsa';
type PromiseLike = Promise<void> | void
declare module 'minecraft-protocol' {
export class Client extends EventEmitter {
constructor(isServer: boolean, version: string, customPackets?: any)
state: States
isServer: boolean
socket: Socket
uuid: string
username: string
session?: SessionOption
profile?: any
deserializer: FullPacketParser
serializer: Serializer
latency: number
customPackets: any
protocolVersion: number
version: string
write(name: string, params: any): void
writeRaw(buffer: any): void
compressionThreshold: string
ended: boolean
connect(port: number, host: string): void
setSocket(socket: Socket): void
end(reason?: string): void
registerChannel(name: string, typeDefinition: any, custom?: boolean): void
unregisterChannel(name: string): void
writeChannel(channel: any, params: any): void
signMessage(message: string, timestamp: BigInt, salt?: number, preview?: string, acknowledgements?: Buffer[]): Buffer
verifyMessage(publicKey: Buffer | KeyObject, packet: object): boolean
reportPlayer(uuid: string, reason: 'FALSE_REPORTING' | 'HATE_SPEECH' | 'TERRORISM_OR_VIOLENT_EXTREMISM' | 'CHILD_SEXUAL_EXPLOITATION_OR_ABUSE' | 'IMMINENT_HARM' | 'NON_CONSENSUAL_INTIMATE_IMAGERY' | 'HARASSMENT_OR_BULLYING' | 'DEFAMATION_IMPERSONATION_FALSE_INFORMATION' | 'SELF_HARM_OR_SUICIDE' | 'ALCOHOL_TOBACCO_DRUGS', signatures: Buffer[], comment?: string): Promise<true>
chat(message: string, options?: { timestamp?: BigInt, salt?: BigInt, preview?: BinaryLike, didPreview?: boolean }): void
on(event: 'error', listener: (error: Error) => PromiseLike): this
on(event: 'packet', handler: (data: any, packetMeta: PacketMeta, buffer: Buffer, fullBuffer: Buffer) => PromiseLike): this
on(event: 'raw', handler: (buffer: Buffer, packetMeta: PacketMeta) => PromiseLike): this
on(event: 'session', handler: (session: SessionObject) => PromiseLike): this
on(event: 'state', handler: (newState: States, oldState: States) => PromiseLike): this
on(event: 'end', handler: (reason: string) => PromiseLike): this
on(event: 'connect', handler: () => PromiseLike): this
on(event: string, handler: (data: any, packetMeta: PacketMeta) => PromiseLike): this
on(event: `raw.${string}`, handler: (buffer: Buffer, packetMeta: PacketMeta) => PromiseLike): this
on(event: 'playerChat', handler: (data: {
// (JSON string) The chat message preformatted, if done on server side
formattedMessage: string,
// (Plaintext) The chat message without formatting (for example no `<username> message` ; instead `message`), on version 1.19+
plainMessage: string,
// (JSON string) Unsigned formatted chat contents. Should only be present when the message is modified and server has chat previews disabled. Only on versions 1.19.0, 1.19.1 and 1.19.2
unsignedContent?: string,
type: string,
sender: string,
senderName: string,
senderTeam: string,
targetName: string,
verified?: boolean
}) => PromiseLike): this
on(event: 'systemChat', handler: (data: { positionId: number, formattedMessage: string }) => PromiseLike): this
// Emitted after the player enters the PLAY state and can send and recieve game packets
on(event: 'playerJoin', handler: () => void): this
once(event: 'error', listener: (error: Error) => PromiseLike): this
once(event: 'packet', handler: (data: any, packetMeta: PacketMeta, buffer: Buffer, fullBuffer: Buffer) => PromiseLike): this
once(event: 'raw', handler: (buffer: Buffer, packetMeta: PacketMeta) => PromiseLike): this
once(event: 'sessionce', handler: (sessionce: any) => PromiseLike): this
once(event: 'state', handler: (newState: States, oldState: States) => PromiseLike): this
once(event: 'end', handler: (reasonce: string) => PromiseLike): this
once(event: 'connect', handler: () => PromiseLike): this
once(event: string, handler: (data: any, packetMeta: PacketMeta) => PromiseLike): this
once(event: `raw.${string}`, handler: (buffer: Buffer, packetMeta: PacketMeta) => PromiseLike): this
}
class FullPacketParser extends Transform {
proto: any
mainType: any
noErrorLogging: boolean
constructor (proto: any, mainType: any, noErrorLogging?: boolean)
parsePacketBuffer(buffer: Buffer): any
}
class Serializer extends Transform {
proto: any
mainType: any
queue: Buffer
constructor(proto: any, mainType: any)
createPacketBuffer(packet: any): any
}
export interface SessionOption {
accessToken: string,
/** My be needed for mojang auth. Is send by mojang on username + password auth */
clientToken?: string,
selectedProfile: SessionProfile
}
export interface SessionObject {
accessToken: string,
/** My be needed for mojang auth. Is send by mojang on username + password auth */
clientToken?: string,
selectedProfile: {
name: string
id: string
}
availableProfiles?: SessionProfile[]
availableProfile?: SessionProfile[]
}
interface SessionProfile {
/** Character in game name */
name: string
/** Character UUID in short form */
id: string
}
export interface ClientOptions {
username: string
port?: number
auth?: 'mojang' | 'microsoft' | 'offline' | ((client: Client, options: ClientOptions) => void)
password?: string
host?: string
clientToken?: string
accessToken?: string
authServer?: string
authTitle?: string
sessionServer?: string
keepAlive?: boolean
closeTimeout?: number
noPongTimeout?: number
checkTimeoutInterval?: number
version?: string
customPackets?: any
hideErrors?: boolean
skipValidation?: boolean
stream?: Stream
connect?: (client: Client) => void
agent?: Agent
fakeHost?: string
profilesFolder?: string | false
onMsaCode?: (data: MicrosoftDeviceAuthorizationResponse) => void
id?: number
session?: SessionOption
validateChannelProtocol?: boolean,
realms?: RealmsOptions
// 1.19+
disableChatSigning?: boolean
/** Pass custom client implementation if needed. */
Client?: Client
}
export class Server extends EventEmitter {
constructor(version: string, customPackets?: any)
writeToClients(clients: Client[], name: string, params: any): void
onlineModeExceptions: object
clients: { [key: number]: ServerClient }
playerCount: number
maxPlayers: number
motd: string
motdMsg?: Object
favicon: string
serverKey: NodeRSA
close(): void
on(event: 'connection', handler: (client: ServerClient) => PromiseLike): this
on(event: 'error', listener: (error: Error) => PromiseLike): this
on(event: 'login', handler: (client: ServerClient) => PromiseLike): this
on(event: 'listening', listener: () => PromiseLike): this
// Emitted after the player enters the PLAY state and can send and recieve game packets
on(event: 'playerJoin', handler: (client: ServerClient) => void): this
once(event: 'connection', handler: (client: ServerClient) => PromiseLike): this
once(event: 'error', listener: (error: Error) => PromiseLike): this
once(event: 'login', handler: (client: ServerClient) => PromiseLike): this
once(event: 'listening', listener: () => PromiseLike): this
}
export interface ServerClient extends Client {
id: number
/** You must call this function when the server receives a message from a player and that message gets
broadcast to other players in player_chat packets. This function stores these packets so the server
can then verify a player's lastSeenMessages field in inbound chat packets to ensure chain integrity. */
logSentMessageFromPeer(packet: object): boolean
}
export interface ServerOptions {
port?: number
host?: string
kickTimeout?: number
checkTimeoutInterval?: number
'online-mode'?: boolean
beforePing?: (response: any, client: Client, callback?: (error: any, result: any) => any) => any
beforeLogin?: (client: Client) => void
motd?: string
motdMsg?: Object
maxPlayers?: number
keepAlive?: boolean
version?: string | false
fallbackVersion?: string
favicon?: string
customPackets?: any
errorHandler?: (client: Client, error: Error) => void
hideErrors?: boolean
agent?: Agent
validateChannelProtocol?: boolean
/** (1.19+) Require connecting clients to have chat signing support enabled */
enforceSecureProfile?: boolean
/** 1.19.1 & 1.19.2 only: If client should send previews of messages they are typing to the server */
enableChatPreview?: boolean
socketType?: 'tcp' | 'ipc'
Server?: Server
}
export interface SerializerOptions {
customPackets: any
isServer?: boolean
state?: States
version: string
}
export interface MicrosoftDeviceAuthorizationResponse {
device_code: string
user_code: string
verification_uri: string
expires_in: number
interval: number
message: string
}
enum States {
HANDSHAKING = 'handshaking',
LOGIN = 'login',
PLAY = 'play',
CONFIGURATION = 'configuration',
STATUS = 'status',
}
export interface PacketMeta {
name: string
state: States
}
export interface PingOptions {
host?: string
majorVersion?: string
port?: number
protocolVersion?: string
version?: string
closeTimeout?: number
noPongTimeout?: number
}
export interface OldPingResult {
maxPlayers: number,
motd: string
playerCount: number
prefix: string
protocol: number
version: string
}
export interface NewPingResult {
description: {
text?: string
extra?: any[]
} | string
players: {
max: number
online: number
sample?: {
id: string
name: string
}[]
}
version: {
name: string
protocol: number
}
favicon?: string
latency: number
}
export interface RealmsOptions {
realmId?: string
pickRealm?: (realms: Realm[]) => Realm
}
export const states: typeof States
export const supportedVersions: string[]
export const defaultVersion: string
export function createServer(options: ServerOptions): Server
export function createClient(options: ClientOptions): Client
// TODO: Create typings on protodef to define here
export function createSerializer({ state, isServer, version, customPackets }: SerializerOptions): any
export function createDeserializer({ state, isServer, version, customPackets }: SerializerOptions): any
export function ping(options: PingOptions, callback?: (error: Error, result: OldPingResult | NewPingResult) => void): Promise<OldPingResult | NewPingResult>
}