mirror of
https://github.com/unmojang/node-minecraft-protocol.git
synced 2025-09-28 13:45:37 -04:00
parent
0ba187d97a
commit
779ffd7ba9
@ -1,6 +1,6 @@
|
|||||||
var Client = require('./client');
|
const Client = require('./client');
|
||||||
var Server = require('./server');
|
const Server = require('./server');
|
||||||
var serializer = require("./transforms/serializer");
|
const serializer = require("./transforms/serializer");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Client: Client,
|
Client: Client,
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
var EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
var debug = require('./debug');
|
const debug = require('./debug');
|
||||||
var compression = require('./transforms/compression');
|
const compression = require('./transforms/compression');
|
||||||
var framing = require('./transforms/framing');
|
const framing = require('./transforms/framing');
|
||||||
var crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
var states = require("./states");
|
const states = require("./states");
|
||||||
|
|
||||||
var createSerializer=require("./transforms/serializer").createSerializer;
|
const createSerializer=require("./transforms/serializer").createSerializer;
|
||||||
var createDeserializer=require("./transforms/serializer").createDeserializer;
|
const createDeserializer=require("./transforms/serializer").createDeserializer;
|
||||||
|
|
||||||
class Client extends EventEmitter
|
class Client extends EventEmitter
|
||||||
{
|
{
|
||||||
@ -30,12 +30,12 @@ class Client extends EventEmitter
|
|||||||
this.latency=0;
|
this.latency=0;
|
||||||
|
|
||||||
this.on('newListener', function(event, listener) {
|
this.on('newListener', function(event, listener) {
|
||||||
var direction = this.isServer ? 'toServer' : 'toClient';
|
const direction = this.isServer ? 'toServer' : 'toClient';
|
||||||
if(typeof this.packetsToParse[event] === "undefined") this.packetsToParse[event] = 1;
|
if(typeof this.packetsToParse[event] === "undefined") this.packetsToParse[event] = 1;
|
||||||
else this.packetsToParse[event] += 1;
|
else this.packetsToParse[event] += 1;
|
||||||
});
|
});
|
||||||
this.on('removeListener', function(event, listener) {
|
this.on('removeListener', function(event, listener) {
|
||||||
var direction = this.isServer ? 'toServer' : 'toClient';
|
const direction = this.isServer ? 'toServer' : 'toClient';
|
||||||
this.packetsToParse[event] -= 1;
|
this.packetsToParse[event] -= 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -53,9 +53,9 @@ class Client extends EventEmitter
|
|||||||
this.splitter.recognizeLegacyPing = state === states.HANDSHAKING;
|
this.splitter.recognizeLegacyPing = state === states.HANDSHAKING;
|
||||||
|
|
||||||
this.serializer.on('error', (e) => {
|
this.serializer.on('error', (e) => {
|
||||||
var parts=e.field.split(".");
|
const parts=e.field.split(".");
|
||||||
parts.shift();
|
parts.shift();
|
||||||
var serializerDirection = !this.isServer ? 'toServer' : 'toClient';
|
const serializerDirection = !this.isServer ? 'toServer' : 'toClient';
|
||||||
e.field = [this.protocolState, serializerDirection].concat(parts).join(".");
|
e.field = [this.protocolState, serializerDirection].concat(parts).join(".");
|
||||||
e.message = `Serialization error for ${e.field} : ${e.message}`;
|
e.message = `Serialization error for ${e.field} : ${e.message}`;
|
||||||
this.emit('error',e);
|
this.emit('error',e);
|
||||||
@ -63,9 +63,9 @@ class Client extends EventEmitter
|
|||||||
|
|
||||||
|
|
||||||
this.deserializer.on('error', (e) => {
|
this.deserializer.on('error', (e) => {
|
||||||
var parts=e.field.split(".");
|
const parts=e.field.split(".");
|
||||||
parts.shift();
|
parts.shift();
|
||||||
var deserializerDirection = this.isServer ? 'toServer' : 'toClient';
|
const deserializerDirection = this.isServer ? 'toServer' : 'toClient';
|
||||||
e.field = [this.protocolState, deserializerDirection].concat(parts).join(".");
|
e.field = [this.protocolState, deserializerDirection].concat(parts).join(".");
|
||||||
e.message = `Deserialization error for ${e.field} : ${e.message}`;
|
e.message = `Deserialization error for ${e.field} : ${e.message}`;
|
||||||
this.emit('error',e);
|
this.emit('error',e);
|
||||||
@ -85,7 +85,7 @@ class Client extends EventEmitter
|
|||||||
}
|
}
|
||||||
|
|
||||||
set state(newProperty) {
|
set state(newProperty) {
|
||||||
var oldProperty = this.protocolState;
|
const oldProperty = this.protocolState;
|
||||||
this.protocolState = newProperty;
|
this.protocolState = newProperty;
|
||||||
|
|
||||||
if(!this.compressor)
|
if(!this.compressor)
|
||||||
@ -129,7 +129,7 @@ class Client extends EventEmitter
|
|||||||
this.ended = false;
|
this.ended = false;
|
||||||
|
|
||||||
// TODO : A lot of other things needs to be done.
|
// TODO : A lot of other things needs to be done.
|
||||||
var endSocket = () => {
|
const endSocket = () => {
|
||||||
if(this.ended) return;
|
if(this.ended) return;
|
||||||
this.ended = true;
|
this.ended = true;
|
||||||
this.socket.removeListener('close', endSocket);
|
this.socket.removeListener('close', endSocket);
|
||||||
@ -138,12 +138,12 @@ class Client extends EventEmitter
|
|||||||
this.emit('end', this._endReason);
|
this.emit('end', this._endReason);
|
||||||
};
|
};
|
||||||
|
|
||||||
var onFatalError = (err) => {
|
const onFatalError = (err) => {
|
||||||
this.emit('error', err);
|
this.emit('error', err);
|
||||||
endSocket();
|
endSocket();
|
||||||
};
|
};
|
||||||
|
|
||||||
var onError = (err) => this.emit('error', err);
|
const onError = (err) => this.emit('error', err);
|
||||||
|
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ class Client extends EventEmitter
|
|||||||
|
|
||||||
// TCP/IP-specific (not generic Stream) method for backwards-compatibility
|
// TCP/IP-specific (not generic Stream) method for backwards-compatibility
|
||||||
connect(port, host) {
|
connect(port, host) {
|
||||||
var options = {port, host};
|
const options = {port, host};
|
||||||
if (!this.options) this.options = options;
|
if (!this.options) this.options = options;
|
||||||
require('./client/tcp_dns')(this, options);
|
require('./client/tcp_dns')(this, options);
|
||||||
options.connect(this);
|
options.connect(this);
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
var yggdrasil = require('yggdrasil')({});
|
const yggdrasil = require('yggdrasil')({});
|
||||||
var UUID = require('uuid-1345');
|
const UUID = require('uuid-1345');
|
||||||
|
|
||||||
module.exports = function(client, options) {
|
module.exports = function(client, options) {
|
||||||
var clientToken = options.clientToken || UUID.v4().toString();
|
const clientToken = options.clientToken || UUID.v4().toString();
|
||||||
options.accessToken = null;
|
options.accessToken = null;
|
||||||
options.haveCredentials = options.password != null || (clientToken != null && options.session != null);
|
options.haveCredentials = options.password != null || (clientToken != null && options.session != null);
|
||||||
|
|
||||||
if(options.haveCredentials) {
|
if(options.haveCredentials) {
|
||||||
// make a request to get the case-correct username before connecting.
|
// make a request to get the case-correct username before connecting.
|
||||||
var cb = function(err, session) {
|
const cb = function(err, session) {
|
||||||
if(err) {
|
if(err) {
|
||||||
client.emit('error', err);
|
client.emit('error', err);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
var crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
var yggserver = require('yggdrasil').server({});
|
const yggserver = require('yggdrasil').server({});
|
||||||
var ursa=require("../ursa");
|
const ursa=require("../ursa");
|
||||||
var debug = require("../debug");
|
const debug = require("../debug");
|
||||||
|
|
||||||
module.exports = function(client, options) {
|
module.exports = function(client, options) {
|
||||||
client.once('encryption_begin', onEncryptionKeyRequest);
|
client.once('encryption_begin', onEncryptionKeyRequest);
|
||||||
@ -40,9 +40,9 @@ module.exports = function(client, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendEncryptionKeyResponse() {
|
function sendEncryptionKeyResponse() {
|
||||||
var pubKey = mcPubKeyToURsa(packet.publicKey);
|
const pubKey = mcPubKeyToURsa(packet.publicKey);
|
||||||
var encryptedSharedSecretBuffer = pubKey.encrypt(sharedSecret, undefined, undefined, ursa.RSA_PKCS1_PADDING);
|
const encryptedSharedSecretBuffer = pubKey.encrypt(sharedSecret, undefined, undefined, ursa.RSA_PKCS1_PADDING);
|
||||||
var encryptedVerifyTokenBuffer = pubKey.encrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING);
|
const encryptedVerifyTokenBuffer = pubKey.encrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING);
|
||||||
client.write('encryption_begin', {
|
client.write('encryption_begin', {
|
||||||
sharedSecret: encryptedSharedSecretBuffer,
|
sharedSecret: encryptedSharedSecretBuffer,
|
||||||
verifyToken: encryptedVerifyTokenBuffer
|
verifyToken: encryptedVerifyTokenBuffer
|
||||||
@ -54,9 +54,9 @@ module.exports = function(client, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function mcPubKeyToURsa(mcPubKeyBuffer) {
|
function mcPubKeyToURsa(mcPubKeyBuffer) {
|
||||||
var pem = "-----BEGIN PUBLIC KEY-----\n";
|
let pem = "-----BEGIN PUBLIC KEY-----\n";
|
||||||
var base64PubKey = mcPubKeyBuffer.toString('base64');
|
let base64PubKey = mcPubKeyBuffer.toString('base64');
|
||||||
var maxLineLength = 65;
|
const maxLineLength = 65;
|
||||||
while(base64PubKey.length > 0) {
|
while(base64PubKey.length > 0) {
|
||||||
pem += base64PubKey.substring(0, maxLineLength) + "\n";
|
pem += base64PubKey.substring(0, maxLineLength) + "\n";
|
||||||
base64PubKey = base64PubKey.substring(maxLineLength);
|
base64PubKey = base64PubKey.substring(maxLineLength);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
module.exports = function(client, options) {
|
module.exports = function(client, options) {
|
||||||
var keepAlive = options.keepAlive == null ? true : options.keepAlive;
|
const keepAlive = options.keepAlive == null ? true : options.keepAlive;
|
||||||
if (!keepAlive) return;
|
if (!keepAlive) return;
|
||||||
|
|
||||||
var checkTimeoutInterval = options.checkTimeoutInterval || 10 * 1000;
|
const checkTimeoutInterval = options.checkTimeoutInterval || 10 * 1000;
|
||||||
|
|
||||||
client.on('keep_alive', onKeepAlive);
|
client.on('keep_alive', onKeepAlive);
|
||||||
|
|
||||||
var timeout = null;
|
let timeout = null;
|
||||||
|
|
||||||
function onKeepAlive(packet) {
|
function onKeepAlive(packet) {
|
||||||
if (timeout)
|
if (timeout)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
var states = require("../states");
|
const states = require("../states");
|
||||||
|
|
||||||
module.exports = function(client, options) {
|
module.exports = function(client, options) {
|
||||||
client.once('success', onLogin);
|
client.once('success', onLogin);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
|
const states = require("../states");
|
||||||
var states = require("../states");
|
|
||||||
|
|
||||||
module.exports = function(client, options) {
|
module.exports = function(client, options) {
|
||||||
client.on('connect', onConnect);
|
client.on('connect', onConnect);
|
||||||
@ -24,4 +23,4 @@ module.exports = function(client, options) {
|
|||||||
username: client.username
|
username: client.username
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
var net = require('net');
|
const net = require('net');
|
||||||
var dns = require('dns');
|
const dns = require('dns');
|
||||||
|
|
||||||
module.exports = function(client, options) {
|
module.exports = function(client, options) {
|
||||||
options.port = options.port || 25565;
|
options.port = options.port || 25565;
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
var Client = require('./client');
|
const Client = require('./client');
|
||||||
var assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
var encrypt = require('./client/encrypt');
|
|
||||||
var keepalive = require('./client/keepalive');
|
const encrypt = require('./client/encrypt');
|
||||||
var compress = require('./client/compress');
|
const keepalive = require('./client/keepalive');
|
||||||
var caseCorrect = require('./client/caseCorrect');
|
const compress = require('./client/compress');
|
||||||
var setProtocol = require('./client/setProtocol');
|
const caseCorrect = require('./client/caseCorrect');
|
||||||
var play = require('./client/play');
|
const setProtocol = require('./client/setProtocol');
|
||||||
var tcp_dns = require('./client/tcp_dns');
|
const play = require('./client/play');
|
||||||
var autoVersion = require('./client/autoVersion');
|
const tcp_dns = require('./client/tcp_dns');
|
||||||
|
const autoVersion = require('./client/autoVersion');
|
||||||
|
|
||||||
module.exports=createClient;
|
module.exports=createClient;
|
||||||
|
|
||||||
@ -17,14 +18,14 @@ function createClient(options) {
|
|||||||
assert.ok(options.username, "username is required");
|
assert.ok(options.username, "username is required");
|
||||||
|
|
||||||
// TODO: avoid setting default version if autoVersion is enabled
|
// TODO: avoid setting default version if autoVersion is enabled
|
||||||
var optVersion = options.version || require("./version").defaultVersion;
|
const optVersion = options.version || require("./version").defaultVersion;
|
||||||
var mcData=require("minecraft-data")(optVersion);
|
const mcData=require("minecraft-data")(optVersion);
|
||||||
if (!mcData) throw new Error(`unsupported protocol version: ${optVersion}`);
|
if (!mcData) throw new Error(`unsupported protocol version: ${optVersion}`);
|
||||||
var version = mcData.version;
|
const version = mcData.version;
|
||||||
options.majorVersion = version.majorVersion;
|
options.majorVersion = version.majorVersion;
|
||||||
options.protocolVersion = version.version;
|
options.protocolVersion = version.version;
|
||||||
|
|
||||||
var client = new Client(false, options.majorVersion);
|
const client = new Client(false, options.majorVersion);
|
||||||
|
|
||||||
tcp_dns(client, options);
|
tcp_dns(client, options);
|
||||||
caseCorrect(client, options);
|
caseCorrect(client, options);
|
||||||
|
@ -1,38 +1,38 @@
|
|||||||
var ursa=require("./ursa");
|
const ursa=require("./ursa");
|
||||||
var crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
var yggserver = require('yggdrasil').server({});
|
const yggserver = require('yggdrasil').server({});
|
||||||
var states = require("./states");
|
const states = require("./states");
|
||||||
var bufferEqual = require('buffer-equal');
|
const bufferEqual = require('buffer-equal');
|
||||||
var Server = require('./server');
|
const Server = require('./server');
|
||||||
var UUID = require('uuid-1345');
|
const UUID = require('uuid-1345');
|
||||||
var endianToggle = require('endian-toggle');
|
const endianToggle = require('endian-toggle');
|
||||||
|
|
||||||
module.exports=createServer;
|
module.exports=createServer;
|
||||||
|
|
||||||
function createServer(options) {
|
function createServer(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var port = options.port != null ?
|
const port = options.port != null ?
|
||||||
options.port :
|
options.port :
|
||||||
options['server-port'] != null ?
|
options['server-port'] != null ?
|
||||||
options['server-port'] :
|
options['server-port'] :
|
||||||
25565;
|
25565;
|
||||||
var host = options.host || '0.0.0.0';
|
const host = options.host || '0.0.0.0';
|
||||||
var kickTimeout = options.kickTimeout || 10 * 1000;
|
const kickTimeout = options.kickTimeout || 10 * 1000;
|
||||||
var checkTimeoutInterval = options.checkTimeoutInterval || 4 * 1000;
|
const checkTimeoutInterval = options.checkTimeoutInterval || 4 * 1000;
|
||||||
var onlineMode = options['online-mode'] == null ? true : options['online-mode'];
|
const onlineMode = options['online-mode'] == null ? true : options['online-mode'];
|
||||||
// a function receiving the default status object and the client
|
// a function receiving the default status object and the client
|
||||||
// and returning a modified response object.
|
// and returning a modified response object.
|
||||||
var beforePing = options.beforePing || null;
|
const beforePing = options.beforePing || null;
|
||||||
|
|
||||||
var enableKeepAlive = options.keepAlive == null ? true : options.keepAlive;
|
const enableKeepAlive = options.keepAlive == null ? true : options.keepAlive;
|
||||||
|
|
||||||
var optVersion = options.version || require("./version").defaultVersion;
|
const optVersion = options.version || require("./version").defaultVersion;
|
||||||
var mcData=require("minecraft-data")(optVersion);
|
const mcData=require("minecraft-data")(optVersion);
|
||||||
var version = mcData.version;
|
const version = mcData.version;
|
||||||
|
|
||||||
var serverKey = ursa.generatePrivateKey(1024);
|
const serverKey = ursa.generatePrivateKey(1024);
|
||||||
|
|
||||||
var server = new Server(version.majorVersion);
|
const server = new Server(version.majorVersion);
|
||||||
server.motd = options.motd || "A Minecraft server";
|
server.motd = options.motd || "A Minecraft server";
|
||||||
server.maxPlayers = options['max-players'] || 20;
|
server.maxPlayers = options['max-players'] || 20;
|
||||||
server.playerCount = 0;
|
server.playerCount = 0;
|
||||||
@ -44,16 +44,16 @@ function createServer(options) {
|
|||||||
client.once('legacy_server_list_ping', onLegacyPing);
|
client.once('legacy_server_list_ping', onLegacyPing);
|
||||||
client.on('end', onEnd);
|
client.on('end', onEnd);
|
||||||
|
|
||||||
var keepAlive = false;
|
let keepAlive = false;
|
||||||
var loggedIn = false;
|
let loggedIn = false;
|
||||||
var lastKeepAlive = null;
|
let lastKeepAlive = null;
|
||||||
|
|
||||||
var keepAliveTimer = null;
|
let keepAliveTimer = null;
|
||||||
var loginKickTimer = setTimeout(kickForNotLoggingIn, kickTimeout);
|
let loginKickTimer = setTimeout(kickForNotLoggingIn, kickTimeout);
|
||||||
|
|
||||||
var serverId;
|
let serverId;
|
||||||
|
|
||||||
var sendKeepAliveTime;
|
let sendKeepAliveTime;
|
||||||
|
|
||||||
function kickForNotLoggingIn() {
|
function kickForNotLoggingIn() {
|
||||||
client.end('LoginTimeout');
|
client.end('LoginTimeout');
|
||||||
@ -64,7 +64,7 @@ function createServer(options) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// check if the last keepAlive was too long ago (kickTimeout)
|
// check if the last keepAlive was too long ago (kickTimeout)
|
||||||
var elapsed = new Date() - lastKeepAlive;
|
const elapsed = new Date() - lastKeepAlive;
|
||||||
if(elapsed > kickTimeout) {
|
if(elapsed > kickTimeout) {
|
||||||
client.end('KeepAliveTimeout');
|
client.end('KeepAliveTimeout');
|
||||||
return;
|
return;
|
||||||
@ -93,7 +93,7 @@ function createServer(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onPing() {
|
function onPing() {
|
||||||
var response = {
|
const response = {
|
||||||
"version": {
|
"version": {
|
||||||
"name": version.minecraftVersion,
|
"name": version.minecraftVersion,
|
||||||
"protocol": version.version
|
"protocol": version.version
|
||||||
@ -130,7 +130,7 @@ function createServer(options) {
|
|||||||
|
|
||||||
function onLegacyPing(packet) {
|
function onLegacyPing(packet) {
|
||||||
if (packet.payload === 1) {
|
if (packet.payload === 1) {
|
||||||
var pingVersion = 1;
|
const pingVersion = 1;
|
||||||
sendPingResponse('\xa7' + [pingVersion, version.version, version.minecraftVersion,
|
sendPingResponse('\xa7' + [pingVersion, version.version, version.minecraftVersion,
|
||||||
server.motd, server.playerCount.toString(), server.maxPlayers.toString()].join('\0'));
|
server.motd, server.playerCount.toString(), server.maxPlayers.toString()].join('\0'));
|
||||||
} else {
|
} else {
|
||||||
@ -143,13 +143,13 @@ function createServer(options) {
|
|||||||
return endianToggle(new Buffer(s, 'utf16le'), 16);
|
return endianToggle(new Buffer(s, 'utf16le'), 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
var responseBuffer = utf16be(responseString);
|
const responseBuffer = utf16be(responseString);
|
||||||
|
|
||||||
var length = responseString.length; // UCS2 characters, not bytes
|
const length = responseString.length; // UCS2 characters, not bytes
|
||||||
var lengthBuffer = new Buffer(2);
|
const lengthBuffer = new Buffer(2);
|
||||||
lengthBuffer.writeUInt16BE(length);
|
lengthBuffer.writeUInt16BE(length);
|
||||||
|
|
||||||
var raw = Buffer.concat([new Buffer('ff', 'hex'), lengthBuffer, responseBuffer]);
|
const raw = Buffer.concat([new Buffer('ff', 'hex'), lengthBuffer, responseBuffer]);
|
||||||
|
|
||||||
//client.writeRaw(raw); // not raw enough, it includes length
|
//client.writeRaw(raw); // not raw enough, it includes length
|
||||||
client.socket.write(raw);
|
client.socket.write(raw);
|
||||||
@ -159,14 +159,14 @@ function createServer(options) {
|
|||||||
|
|
||||||
function onLogin(packet) {
|
function onLogin(packet) {
|
||||||
client.username = packet.username;
|
client.username = packet.username;
|
||||||
var isException = !!server.onlineModeExceptions[client.username.toLowerCase()];
|
const isException = !!server.onlineModeExceptions[client.username.toLowerCase()];
|
||||||
var needToVerify = (onlineMode && !isException) || (!onlineMode && isException);
|
const needToVerify = (onlineMode && !isException) || (!onlineMode && isException);
|
||||||
if(needToVerify) {
|
if(needToVerify) {
|
||||||
serverId = crypto.randomBytes(4).toString('hex');
|
serverId = crypto.randomBytes(4).toString('hex');
|
||||||
client.verifyToken = crypto.randomBytes(4);
|
client.verifyToken = crypto.randomBytes(4);
|
||||||
var publicKeyStrArr = serverKey.toPublicPem("utf8").split("\n");
|
const publicKeyStrArr = serverKey.toPublicPem("utf8").split("\n");
|
||||||
var publicKeyStr = "";
|
let publicKeyStr = "";
|
||||||
for(var i = 1; i < publicKeyStrArr.length - 2; i++) {
|
for(let i = 1; i < publicKeyStrArr.length - 2; i++) {
|
||||||
publicKeyStr += publicKeyStrArr[i]
|
publicKeyStr += publicKeyStrArr[i]
|
||||||
}
|
}
|
||||||
client.publicKey = new Buffer(publicKeyStr, 'base64');
|
client.publicKey = new Buffer(publicKeyStr, 'base64');
|
||||||
@ -198,21 +198,21 @@ function createServer(options) {
|
|||||||
|
|
||||||
function onEncryptionKeyResponse(packet) {
|
function onEncryptionKeyResponse(packet) {
|
||||||
try {
|
try {
|
||||||
var verifyToken = serverKey.decrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING);
|
const verifyToken = serverKey.decrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING);
|
||||||
if(!bufferEqual(client.verifyToken, verifyToken)) {
|
if(!bufferEqual(client.verifyToken, verifyToken)) {
|
||||||
client.end('DidNotEncryptVerifyTokenProperly');
|
client.end('DidNotEncryptVerifyTokenProperly');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var sharedSecret = serverKey.decrypt(packet.sharedSecret, undefined, undefined, ursa.RSA_PKCS1_PADDING);
|
const sharedSecret = serverKey.decrypt(packet.sharedSecret, undefined, undefined, ursa.RSA_PKCS1_PADDING);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
client.end('DidNotEncryptVerifyTokenProperly');
|
client.end('DidNotEncryptVerifyTokenProperly');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
client.setEncryption(sharedSecret);
|
client.setEncryption(sharedSecret);
|
||||||
|
|
||||||
var isException = !!server.onlineModeExceptions[client.username.toLowerCase()];
|
const isException = !!server.onlineModeExceptions[client.username.toLowerCase()];
|
||||||
var needToVerify = (onlineMode && !isException) || (!onlineMode && isException);
|
const needToVerify = (onlineMode && !isException) || (!onlineMode && isException);
|
||||||
var nextStep = needToVerify ? verifyUsername : loginClient;
|
const nextStep = needToVerify ? verifyUsername : loginClient;
|
||||||
nextStep();
|
nextStep();
|
||||||
|
|
||||||
function verifyUsername() {
|
function verifyUsername() {
|
||||||
@ -234,9 +234,9 @@ function createServer(options) {
|
|||||||
// https://github.com/openjdk-mirror/jdk7u-jdk/blob/f4d80957e89a19a29bb9f9807d2a28351ed7f7df/src/share/classes/java/util/UUID.java#L163
|
// https://github.com/openjdk-mirror/jdk7u-jdk/blob/f4d80957e89a19a29bb9f9807d2a28351ed7f7df/src/share/classes/java/util/UUID.java#L163
|
||||||
function javaUUID(s)
|
function javaUUID(s)
|
||||||
{
|
{
|
||||||
var hash = crypto.createHash("md5");
|
const hash = crypto.createHash("md5");
|
||||||
hash.update(s, 'utf8');
|
hash.update(s, 'utf8');
|
||||||
var buffer = hash.digest();
|
const buffer = hash.digest();
|
||||||
buffer[6] = (buffer[6] & 0x0f) | 0x30;
|
buffer[6] = (buffer[6] & 0x0f) | 0x30;
|
||||||
buffer[8] = (buffer[8] & 0x3f) | 0x80;
|
buffer[8] = (buffer[8] & 0x3f) | 0x80;
|
||||||
return buffer;
|
return buffer;
|
||||||
@ -248,7 +248,7 @@ function createServer(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loginClient() {
|
function loginClient() {
|
||||||
var isException = !!server.onlineModeExceptions[client.username.toLowerCase()];
|
const isException = !!server.onlineModeExceptions[client.username.toLowerCase()];
|
||||||
if(onlineMode == false || isException) {
|
if(onlineMode == false || isException) {
|
||||||
client.uuid = nameToMcOfflineUUID(client.username);
|
client.uuid = nameToMcOfflineUUID(client.username);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
var nbt = require('prismarine-nbt');
|
const nbt = require('prismarine-nbt');
|
||||||
var UUID = require('uuid-1345');
|
const UUID = require('uuid-1345');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
'UUID': [readUUID, writeUUID, 16],
|
'UUID': [readUUID, writeUUID, 16],
|
||||||
@ -17,7 +17,7 @@ function readUUID(buffer, offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function writeUUID(value, buffer, offset) {
|
function writeUUID(value, buffer, offset) {
|
||||||
var buf=UUID.parse(value);
|
const buf=UUID.parse(value);
|
||||||
buf.copy(buffer,offset);
|
buf.copy(buffer,offset);
|
||||||
return offset + 16;
|
return offset + 16;
|
||||||
}
|
}
|
||||||
@ -71,9 +71,9 @@ function sizeOfRestBuffer(value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readEntityMetadata(buffer, offset, {type,endVal}) {
|
function readEntityMetadata(buffer, offset, {type,endVal}) {
|
||||||
var cursor = offset;
|
let cursor = offset;
|
||||||
var metadata = [];
|
const metadata = [];
|
||||||
var item;
|
let item;
|
||||||
while(true) {
|
while(true) {
|
||||||
item = buffer.readUInt8(cursor);
|
item = buffer.readUInt8(cursor);
|
||||||
if(item === endVal) {
|
if(item === endVal) {
|
||||||
@ -82,14 +82,14 @@ function readEntityMetadata(buffer, offset, {type,endVal}) {
|
|||||||
size: cursor + 1 - offset
|
size: cursor + 1 - offset
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
var results = this.read(buffer, cursor, type, {});
|
const results = this.read(buffer, cursor, type, {});
|
||||||
metadata.push(results.value);
|
metadata.push(results.value);
|
||||||
cursor += results.size;
|
cursor += results.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeEntityMetadata(value, buffer, offset, {type,endVal}) {
|
function writeEntityMetadata(value, buffer, offset, {type,endVal}) {
|
||||||
var self = this;
|
const self = this;
|
||||||
value.forEach(function(item) {
|
value.forEach(function(item) {
|
||||||
offset = self.write(item, buffer, offset, type, {});
|
offset = self.write(item, buffer, offset, type, {});
|
||||||
});
|
});
|
||||||
@ -98,8 +98,8 @@ function writeEntityMetadata(value, buffer, offset, {type,endVal}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sizeOfEntityMetadata(value, {type}) {
|
function sizeOfEntityMetadata(value, {type}) {
|
||||||
var size = 1;
|
let size = 1;
|
||||||
for(var i = 0; i < value.length; ++i) {
|
for(let i = 0; i < value.length; ++i) {
|
||||||
size += this.sizeOf(value[i], type, {});
|
size += this.sizeOf(value[i], type, {});
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
var util = require('util');
|
const util = require('util');
|
||||||
|
|
||||||
var debug;
|
let debug;
|
||||||
if(process.env.NODE_DEBUG && /(minecraft-protocol|mc-proto)/.test(process.env.NODE_DEBUG)) {
|
if(process.env.NODE_DEBUG && /(minecraft-protocol|mc-proto)/.test(process.env.NODE_DEBUG)) {
|
||||||
var pid = process.pid;
|
const pid = process.pid;
|
||||||
debug = function(x) {
|
debug = function(x) {
|
||||||
// if console is not set up yet, then skip this.
|
// if console is not set up yet, then skip this.
|
||||||
if(!console.error)
|
if(!console.error)
|
||||||
|
10
src/index.js
10
src/index.js
@ -1,8 +1,8 @@
|
|||||||
var Client = require('./client');
|
const Client = require('./client');
|
||||||
var Server = require('./server');
|
const Server = require('./server');
|
||||||
var serializer = require("./transforms/serializer");
|
const serializer = require("./transforms/serializer");
|
||||||
var createClient = require("./createClient");
|
const createClient = require("./createClient");
|
||||||
var createServer = require("./createServer");
|
const createServer = require("./createServer");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createClient: createClient,
|
createClient: createClient,
|
||||||
|
20
src/ping.js
20
src/ping.js
@ -1,27 +1,27 @@
|
|||||||
var net = require('net');
|
const net = require('net');
|
||||||
var Client = require('./client');
|
const Client = require('./client');
|
||||||
var states = require("./states");
|
const states = require("./states");
|
||||||
var tcp_dns = require('./client/tcp_dns');
|
const tcp_dns = require('./client/tcp_dns');
|
||||||
|
|
||||||
module.exports = ping;
|
module.exports = ping;
|
||||||
|
|
||||||
function ping(options, cb) {
|
function ping(options, cb) {
|
||||||
options.host = options.host || 'localhost';
|
options.host = options.host || 'localhost';
|
||||||
options.port = options.port || 25565;
|
options.port = options.port || 25565;
|
||||||
var optVersion = options.version || require("./version").defaultVersion;
|
const optVersion = options.version || require("./version").defaultVersion;
|
||||||
var mcData=require("minecraft-data")(optVersion);
|
const mcData=require("minecraft-data")(optVersion);
|
||||||
var version = mcData.version;
|
const version = mcData.version;
|
||||||
options.majorVersion = version.majorVersion;
|
options.majorVersion = version.majorVersion;
|
||||||
options.protocolVersion = version.version;
|
options.protocolVersion = version.version;
|
||||||
|
|
||||||
var client = new Client(false,options.majorVersion);
|
const client = new Client(false,options.majorVersion);
|
||||||
client.on('error', function(err) {
|
client.on('error', function(err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
client.once('server_info', function(packet) {
|
client.once('server_info', function(packet) {
|
||||||
var data = JSON.parse(packet.response);
|
const data = JSON.parse(packet.response);
|
||||||
var start = Date.now();
|
const start = Date.now();
|
||||||
client.once('ping', function(packet) {
|
client.once('ping', function(packet) {
|
||||||
data.latency = Date.now() - start;
|
data.latency = Date.now() - start;
|
||||||
cb(null, data);
|
cb(null, data);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
var net = require('net');
|
const net = require('net');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
var Client = require('./client');
|
const Client = require('./client');
|
||||||
var states = require("./states");
|
const states = require("./states");
|
||||||
|
|
||||||
class Server extends EventEmitter
|
class Server extends EventEmitter
|
||||||
{
|
{
|
||||||
@ -15,11 +15,11 @@ class Server extends EventEmitter
|
|||||||
}
|
}
|
||||||
|
|
||||||
listen(port, host) {
|
listen(port, host) {
|
||||||
var self = this;
|
const self = this;
|
||||||
var nextId = 0;
|
let nextId = 0;
|
||||||
self.socketServer = net.createServer();
|
self.socketServer = net.createServer();
|
||||||
self.socketServer.on('connection', socket => {
|
self.socketServer.on('connection', socket => {
|
||||||
var client = new Client(true,this.version);
|
const client = new Client(true,this.version);
|
||||||
client._end = client.end;
|
client._end = client.end;
|
||||||
client.end = function end(endReason) {
|
client.end = function end(endReason) {
|
||||||
endReason='{"text":"'+endReason+'"}';
|
endReason='{"text":"'+endReason+'"}';
|
||||||
@ -51,13 +51,10 @@ class Server extends EventEmitter
|
|||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
var client;
|
Object.keys(this.clients).forEach(clientId => {
|
||||||
for(var clientId in this.clients) {
|
const client = this.clients[clientId];
|
||||||
if(!this.clients.hasOwnProperty(clientId)) continue;
|
|
||||||
|
|
||||||
client = this.clients[clientId];
|
|
||||||
client.end('ServerShutdown');
|
client.end('ServerShutdown');
|
||||||
}
|
});
|
||||||
this.socketServer.close();
|
this.socketServer.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
var states = {
|
const states = {
|
||||||
"HANDSHAKING": "handshaking",
|
"HANDSHAKING": "handshaking",
|
||||||
"STATUS": "status",
|
"STATUS": "status",
|
||||||
"LOGIN": "login",
|
"LOGIN": "login",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
var [readVarInt, writeVarInt, sizeOfVarInt] = require("protodef").types.varint;
|
const [readVarInt, writeVarInt, sizeOfVarInt] = require("protodef").types.varint;
|
||||||
var zlib = require("zlib");
|
const zlib = require("zlib");
|
||||||
var Transform = require("readable-stream").Transform;
|
const Transform = require("readable-stream").Transform;
|
||||||
|
|
||||||
module.exports.createCompressor = function(threshold) {
|
module.exports.createCompressor = function(threshold) {
|
||||||
return new Compressor(threshold);
|
return new Compressor(threshold);
|
||||||
@ -22,8 +22,8 @@ class Compressor extends Transform {
|
|||||||
zlib.deflate(chunk, (err, newChunk) => {
|
zlib.deflate(chunk, (err, newChunk) => {
|
||||||
if (err)
|
if (err)
|
||||||
return cb(err);
|
return cb(err);
|
||||||
var buf = new Buffer(sizeOfVarInt(chunk.length) + newChunk.length);
|
const buf = new Buffer(sizeOfVarInt(chunk.length) + newChunk.length);
|
||||||
var offset = writeVarInt(chunk.length, buf, 0);
|
const offset = writeVarInt(chunk.length, buf, 0);
|
||||||
newChunk.copy(buf, offset);
|
newChunk.copy(buf, offset);
|
||||||
this.push(buf);
|
this.push(buf);
|
||||||
return cb();
|
return cb();
|
||||||
@ -31,8 +31,8 @@ class Compressor extends Transform {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var buf = new Buffer(sizeOfVarInt(0) + chunk.length);
|
const buf = new Buffer(sizeOfVarInt(0) + chunk.length);
|
||||||
var offset = writeVarInt(0, buf, 0);
|
const offset = writeVarInt(0, buf, 0);
|
||||||
chunk.copy(buf, offset);
|
chunk.copy(buf, offset);
|
||||||
this.push(buf);
|
this.push(buf);
|
||||||
return cb();
|
return cb();
|
||||||
@ -47,7 +47,7 @@ class Decompressor extends Transform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_transform(chunk, enc, cb) {
|
_transform(chunk, enc, cb) {
|
||||||
var { size, value, error } = readVarInt(chunk, 0);
|
const { size, value, error } = readVarInt(chunk, 0);
|
||||||
if (error)
|
if (error)
|
||||||
return cb(error);
|
return cb(error);
|
||||||
if (value === 0)
|
if (value === 0)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
var [readVarInt, writeVarInt, sizeOfVarInt] = require("protodef").types.varint;
|
const [readVarInt, writeVarInt, sizeOfVarInt] = require("protodef").types.varint;
|
||||||
var Transform = require("readable-stream").Transform;
|
const Transform = require("readable-stream").Transform;
|
||||||
|
|
||||||
module.exports.createSplitter = function() {
|
module.exports.createSplitter = function() {
|
||||||
return new Splitter();
|
return new Splitter();
|
||||||
@ -16,7 +16,7 @@ class Framer extends Transform {
|
|||||||
|
|
||||||
_transform(chunk, enc, cb) {
|
_transform(chunk, enc, cb) {
|
||||||
const varIntSize=sizeOfVarInt(chunk.length);
|
const varIntSize=sizeOfVarInt(chunk.length);
|
||||||
var buffer = new Buffer(varIntSize + chunk.length);
|
const buffer = new Buffer(varIntSize + chunk.length);
|
||||||
writeVarInt(chunk.length, buffer, 0);
|
writeVarInt(chunk.length, buffer, 0);
|
||||||
chunk.copy(buffer, varIntSize);
|
chunk.copy(buffer, varIntSize);
|
||||||
this.push(buffer);
|
this.push(buffer);
|
||||||
@ -38,17 +38,17 @@ class Splitter extends Transform {
|
|||||||
if (this.recognizeLegacyPing && this.buffer[0] === LEGACY_PING_PACKET_ID) {
|
if (this.recognizeLegacyPing && this.buffer[0] === LEGACY_PING_PACKET_ID) {
|
||||||
// legacy_server_list_ping packet follows a different protocol format
|
// legacy_server_list_ping packet follows a different protocol format
|
||||||
// prefix the encoded varint packet id for the deserializer
|
// prefix the encoded varint packet id for the deserializer
|
||||||
var header = new Buffer(sizeOfVarInt(LEGACY_PING_PACKET_ID));
|
const header = new Buffer(sizeOfVarInt(LEGACY_PING_PACKET_ID));
|
||||||
writeVarInt(LEGACY_PING_PACKET_ID, header, 0);
|
writeVarInt(LEGACY_PING_PACKET_ID, header, 0);
|
||||||
var payload = this.buffer.slice(1); // remove 0xfe packet id
|
let payload = this.buffer.slice(1); // remove 0xfe packet id
|
||||||
if (payload.length === 0) payload = new Buffer('\0'); // TODO: update minecraft-data to recognize a lone 0xfe, https://github.com/PrismarineJS/minecraft-data/issues/95
|
if (payload.length === 0) payload = new Buffer('\0'); // TODO: update minecraft-data to recognize a lone 0xfe, https://github.com/PrismarineJS/minecraft-data/issues/95
|
||||||
this.push(Buffer.concat([header, payload]));
|
this.push(Buffer.concat([header, payload]));
|
||||||
return cb();
|
return cb();
|
||||||
}
|
}
|
||||||
|
|
||||||
var offset = 0;
|
let offset = 0;
|
||||||
|
|
||||||
var { value, size, error } = readVarInt(this.buffer, offset) || { error: "Not enough data" };
|
let { value, size, error } = readVarInt(this.buffer, offset) || { error: "Not enough data" };
|
||||||
while (!error && this.buffer.length >= offset + size + value)
|
while (!error && this.buffer.length >= offset + size + value)
|
||||||
{
|
{
|
||||||
this.push(this.buffer.slice(offset + size, offset + size + value));
|
this.push(this.buffer.slice(offset + size, offset + size + value));
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
var ProtoDef = require("protodef").ProtoDef;
|
const ProtoDef = require("protodef").ProtoDef;
|
||||||
var Serializer = require("protodef").Serializer;
|
const Serializer = require("protodef").Serializer;
|
||||||
var Parser = require("protodef").Parser;
|
const Parser = require("protodef").Parser;
|
||||||
|
|
||||||
var minecraft = require("../datatypes/minecraft");
|
const minecraft = require("../datatypes/minecraft");
|
||||||
var states = require("../states");
|
const states = require("../states");
|
||||||
|
|
||||||
function createProtocol(types,packets)
|
function createProtocol(types,packets)
|
||||||
{
|
{
|
||||||
var proto = new ProtoDef();
|
const proto = new ProtoDef();
|
||||||
proto.addType("string",["pstring",{
|
proto.addType("string",["pstring",{
|
||||||
countType:"varint"
|
countType:"varint"
|
||||||
}]);
|
}]);
|
||||||
@ -38,20 +38,20 @@ function createProtocol(types,packets)
|
|||||||
|
|
||||||
function createSerializer({ state = states.HANDSHAKING, isServer = false , version} = {})
|
function createSerializer({ state = states.HANDSHAKING, isServer = false , version} = {})
|
||||||
{
|
{
|
||||||
var mcData=require("minecraft-data")(version);
|
const mcData=require("minecraft-data")(version);
|
||||||
var direction = !isServer ? 'toServer' : 'toClient';
|
const direction = !isServer ? 'toServer' : 'toClient';
|
||||||
var packets = mcData.protocol.states[state][direction];
|
const packets = mcData.protocol.states[state][direction];
|
||||||
var proto=createProtocol(mcData.protocol.types,packets);
|
const proto=createProtocol(mcData.protocol.types,packets);
|
||||||
return new Serializer(proto,"packet");
|
return new Serializer(proto,"packet");
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDeserializer({ state = states.HANDSHAKING, isServer = false,
|
function createDeserializer({ state = states.HANDSHAKING, isServer = false,
|
||||||
packetsToParse = {"packet": true}, version } = {})
|
packetsToParse = {"packet": true}, version } = {})
|
||||||
{
|
{
|
||||||
var mcData=require("minecraft-data")(version);
|
const mcData=require("minecraft-data")(version);
|
||||||
var direction = isServer ? "toServer" : "toClient";
|
const direction = isServer ? "toServer" : "toClient";
|
||||||
var packets = mcData.protocol.states[state][direction];
|
const packets = mcData.protocol.states[state][direction];
|
||||||
var proto=createProtocol(mcData.protocol.types,packets);
|
const proto=createProtocol(mcData.protocol.types,packets);
|
||||||
return new Parser(proto,"packet");
|
return new Parser(proto,"packet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
var ursa;
|
let ursa;
|
||||||
try {
|
try {
|
||||||
ursa = require("ursa");
|
ursa = require("ursa");
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user