getting encryption request

This commit is contained in:
Andrew Kelley 2012-12-31 20:33:35 -05:00
parent 46c6aeb86e
commit 043cbd5882
5 changed files with 268 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/node_modules

173
lib/parser.js Normal file
View File

@ -0,0 +1,173 @@
var net = require('net')
, EventEmitter = require('events').EventEmitter
, util = require('util')
, assert = require('assert')
, Iconv = require('iconv').Iconv
, packets = require('../packets.json')
, toUcs2 = new Iconv('UTF-8', 'utf16be')
, fromUcs2 = new Iconv('utf16be', 'UTF-8')
module.exports = Parser;
function Parser(options) {
EventEmitter.call(this);
}
util.inherits(Parser, EventEmitter);
Parser.prototype.connect = function(port, host) {
var self = this;
self.client = net.connect(port, host, function() {
self.emit('connect');
});
var incomingBuffer = new Buffer(0);
self.client.on('data', function(data) {
incomingBuffer = Buffer.concat([incomingBuffer, data]);
var parsed;
while (true) {
parsed = parsePacket(incomingBuffer);
if (! parsed) break;
incomingBuffer = incomingBuffer.slice(parsed.size);
self.emit('packet', parsed.results);
}
});
self.client.on('error', function(err) {
self.emit('error', err);
});
self.client.on('end', function() {
self.emit('end');
});
};
Parser.prototype.writePacket = function(packetId, params) {
var buffer = createPacketBuffer(packetId, params);
this.client.write(buffer);
};
var writers = {
'int': IntWriter,
'byte': ByteWriter,
'string': StringWriter,
};
var readers = {
'string': readString,
'byteArray': readByteArray,
'short': readShort,
};
function readString (buffer, offset) {
var results = readShort(buffer, offset);
if (! results) return null;
var strBegin = offset + results.size;
var strLen = results.value;
var strEnd = strBegin + strLen * 2;
if (strEnd > buffer.length) return null;
var str = fromUcs2.convert(buffer.slice(strBegin, strEnd)).toString();
return {
value: str,
size: strEnd - offset,
};
}
function readByteArray (buffer, offset) {
var results = readShort(buffer, offset);
if (! results) return null;
var bytesBegin = offset + results.size;
var bytesSize = results.value;
var bytesEnd = bytesBegin + bytesSize;
if (bytesEnd > buffer.length) return null;
var bytes = buffer.slice(bytesBegin, bytesEnd);
return {
value: bytes,
size: bytesEnd - offset,
};
}
function readShort(buffer, offset) {
if (offset + 2 > buffer.length) return null;
var value = buffer.readInt16BE(offset);
return {
value: value,
size: 2,
};
}
function StringWriter(value) {
this.value = value;
this.encoded = toUcs2.convert(value);
this.size = 2 + this.encoded.length;
}
StringWriter.prototype.write = function(buffer, offset) {
buffer.writeInt16BE(this.value.length, offset);
this.encoded.copy(buffer, offset + 2);
}
function ByteWriter(value) {
this.value = value;
this.size = 1;
}
ByteWriter.prototype.write = function(buffer, offset) {
buffer.writeInt8(this.value, offset);
}
function IntWriter(value) {
this.value = value;
this.size = 4;
}
IntWriter.prototype.write = function(buffer, offset) {
buffer.writeInt32BE(this.value, offset);
}
function createPacketBuffer(packetId, params) {
var size = 1;
var fields = [ new ByteWriter(packetId) ];
var packet = packets[packetId];
packet.forEach(function(fieldInfo) {
var value = params[fieldInfo.name];
var field = new writers[fieldInfo.type](value);
size += field.size;
fields.push(field);
});
var buffer = new Buffer(size);
var cursor = 0;
fields.forEach(function(field) {
field.write(buffer, cursor);
cursor += field.size;
});
return buffer;
}
function parsePacket(buffer) {
if (buffer.length < 1) return null;
var packetId = buffer.readUInt8(0);
var size = 1;
var results = { id: packetId };
var packetInfo = packets[packetId];
assert.ok(packetInfo, "Unrecognized packetId: " + packetId);
var i, fieldInfo, read, readResults;
for (i = 0; i < packetInfo.length; ++i) {
fieldInfo = packetInfo[i];
read = readers[fieldInfo.type];
readResults = read(buffer, size);
if (readResults) {
results[fieldInfo.name] = readResults.value;
size += readResults.size;
} else {
// buffer needs to be more full
return null;
}
}
return {
size: size,
results: results,
};
}

15
package.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "minecraft-protocol",
"version": "0.0.0",
"description": "minecraft protocol",
"main": "index.js",
"scripts": {
"test": "mocha"
},
"keywords": [
"minecraft",
"protocol"
],
"author": "Andrew Kelley",
"license": "BSD",
}

34
packets.json Normal file
View File

@ -0,0 +1,34 @@
{
"2": [
{
"name": "protocolVersion",
"type": "byte"
},
{
"name": "userName",
"type": "string"
},
{
"name": "serverHost",
"type": "string"
},
{
"name": "serverPort",
"type": "int"
}
],
"253": [
{
"name": "serverId",
"type": "string"
},
{
"name": "publicKey",
"type": "byteArray"
},
{
"name": "verifyToken",
"type": "byteArray"
}
]
}

45
test.js Normal file
View File

@ -0,0 +1,45 @@
var Parser = require('./lib/parser');
var parser = new Parser();
parser.on('connect', function() {
console.info("connect");
parser.writePacket(0x02, {
protocolVersion: 51,
userName: 'superjoe30',
serverHost: 'localhost',
serverPort: 25565,
});
});
parser.on('packet', function(packet) {
var handler = packetHandlers[packet.id];
if (handler) {
handler(packet);
} else {
console.warn("No packet handler for", packet.id, "fields", packet);
}
});
parser.on('error', function(err) {
console.error("error connecting", err.stack);
});
parser.on('end', function() {
console.info("disconnect");
});
parser.connect(25565, 'localhost');
var packetHandlers = {
0xFD: onEncryptionKeyRequest,
};
function onEncryptionKeyRequest(packet) {
var sharedSecret = randomBuffer(16);
}
function randomBuffer(size) {
var buffer = new Buffer(size);
var i, number;
for (i = 0; i < size; ++i) {
number = Math.floor(Math.random() * 256);
buffer.writeUInt8(number, i);
}
return buffer;
}