minecraft-protocol
Advanced tools
Comparing version 0.7.4 to 0.7.5
95
index.js
@@ -6,2 +6,3 @@ var EventEmitter = require('events').EventEmitter | ||
, crypto = require('crypto') | ||
, bufferEqual = require('buffer-equal') | ||
, superagent = require('superagent') | ||
@@ -39,2 +40,3 @@ , protocol = require('./lib/protocol') | ||
var server = new Server(options); | ||
server.onlineModeExceptions = {}; | ||
server.maxPlayers = maxPlayers; | ||
@@ -106,4 +108,6 @@ server.on("connection", function(client) { | ||
client.username = packet.username; | ||
var isException = !!server.onlineModeExceptions[client.username]; | ||
var needToVerify = (onlineMode && ! isException) || (! onlineMode && isException); | ||
var serverId; | ||
if (onlineMode) { | ||
if (needToVerify) { | ||
serverId = crypto.randomBytes(4).toString('hex'); | ||
@@ -134,46 +138,51 @@ } else { | ||
function onEncryptionKeyResponse(packet) { | ||
var success = client.verifyToken.toString("hex") === serverKey.decrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING).toString("hex"); | ||
if (success) { | ||
var sharedSecret = serverKey.decrypt(packet.sharedSecret, undefined, undefined, ursa.RSA_PKCS1_PADDING); | ||
client.cipher = crypto.createCipheriv('aes-128-cfb8', sharedSecret, sharedSecret); | ||
client.decipher = crypto.createDecipheriv('aes-128-cfb8', sharedSecret, sharedSecret); | ||
hash.update(sharedSecret); | ||
hash.update(client.publicKey); | ||
var verifyToken = serverKey.decrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING); | ||
if (! bufferEqual(client.verifyToken, verifyToken)) { | ||
client.end('DidNotEncryptVerifyTokenProperly'); | ||
return; | ||
} | ||
var sharedSecret = serverKey.decrypt(packet.sharedSecret, undefined, undefined, ursa.RSA_PKCS1_PADDING); | ||
client.cipher = crypto.createCipheriv('aes-128-cfb8', sharedSecret, sharedSecret); | ||
client.decipher = crypto.createDecipheriv('aes-128-cfb8', sharedSecret, sharedSecret); | ||
hash.update(sharedSecret); | ||
hash.update(client.publicKey); | ||
client.write(0xFC, { | ||
sharedSecret: new Buffer(0), | ||
verifyToken: new Buffer(0) | ||
}); | ||
client.encryptionEnabled = true; | ||
var isException = !!server.onlineModeExceptions[client.username]; | ||
var needToVerify = (onlineMode && ! isException) || (! onlineMode && isException); | ||
var nextStep = needToVerify ? verifyUsername : loginClient; | ||
nextStep(); | ||
function verifyUsername() { | ||
var digest = mcHexDigest(hash); | ||
if (onlineMode) { | ||
var request = superagent.get("http://session.minecraft.net/game/checkserver.jsp"); | ||
request.query({ | ||
user: client.username, | ||
serverId: digest | ||
}); | ||
request.end(function(err, resp) { | ||
var myErr; | ||
if (err) { | ||
server.emit('error', err); | ||
client.end('McSessionUnavailable'); | ||
} else if (resp.serverError) { | ||
myErr = new Error("session.minecraft.net is broken: " + resp.status); | ||
myErr.code = 'EMCSESSION500'; | ||
server.emit('error', myErr); | ||
client.end('McSessionDown'); | ||
} else if (resp.serverError) { | ||
myErr = new Error("session.minecraft.net rejected request: " + resp.status); | ||
myErr.code = 'EMCSESSION400'; | ||
server.emit('error', myErr); | ||
client.end('McSessionRejectedAuthRequest'); | ||
} else if (resp.text !== "YES") { | ||
client.end('FailedToVerifyUsername'); | ||
} else { | ||
loginClient(); | ||
} | ||
}); | ||
} | ||
client.write(0xFC, { | ||
sharedSecret: new Buffer(0), | ||
verifyToken: new Buffer(0) | ||
var request = superagent.get("http://session.minecraft.net/game/checkserver.jsp"); | ||
request.query({ | ||
user: client.username, | ||
serverId: digest | ||
}); | ||
client.encryptionEnabled = true; | ||
if (! onlineMode) loginClient(); | ||
} else { | ||
client.end('DidNotEncryptVerifyTokenProperly'); | ||
request.end(function(err, resp) { | ||
var myErr; | ||
if (err) { | ||
server.emit('error', err); | ||
client.end('McSessionUnavailable'); | ||
} else if (resp.serverError) { | ||
myErr = new Error("session.minecraft.net is broken: " + resp.status); | ||
myErr.code = 'EMCSESSION500'; | ||
server.emit('error', myErr); | ||
client.end('McSessionDown'); | ||
} else if (resp.serverError) { | ||
myErr = new Error("session.minecraft.net rejected request: " + resp.status); | ||
myErr.code = 'EMCSESSION400'; | ||
server.emit('error', myErr); | ||
client.end('McSessionRejectedAuthRequest'); | ||
} else if (resp.text !== "YES") { | ||
client.end('FailedToVerifyUsername'); | ||
} else { | ||
loginClient(); | ||
} | ||
}); | ||
} | ||
@@ -180,0 +189,0 @@ } |
{ | ||
"name": "minecraft-protocol", | ||
"version": "0.7.4", | ||
"version": "0.7.5", | ||
"description": "Parse and serialize minecraft packets, plus authentication and encryption.", | ||
@@ -37,4 +37,5 @@ "main": "index.js", | ||
"ursa": "~0.8.0", | ||
"superagent": "~0.10.0" | ||
"superagent": "~0.10.0", | ||
"buffer-equal": "0.0.0" | ||
} | ||
} |
@@ -111,2 +111,15 @@ # minecraft protocol | ||
### mc.createServer(options) | ||
Returns a `Server` instance and starts listening. | ||
### Server | ||
#### server.onlineModeExceptions | ||
This is a plain old JavaScript object. Add a key with the username you want to | ||
be exempt from online mode or offline mode (whatever mode the server is in). | ||
#### server.maxPlayers | ||
### Not Immediately Obvious Data Type Formats | ||
@@ -235,2 +248,8 @@ | ||
### 0.7.5 | ||
* server: add `onlineModeExceptions`. When server is in: | ||
- online mode: these usernames are exempt from online mode. | ||
- offline mode: these usernames must authenticate. | ||
### 0.7.4 | ||
@@ -237,0 +256,0 @@ |
81346
2376
317
3
+ Addedbuffer-equal@0.0.0
+ Addedbuffer-equal@0.0.0(transitive)