mirror of
https://github.com/unmojang/node-minecraft-protocol.git
synced 2025-09-28 13:45:37 -04:00
ability to exempt usernames from online mode or offline mode
This commit is contained in:
parent
666a24ed9e
commit
cd7f867d95
13
README.md
13
README.md
@ -108,6 +108,19 @@ server.on('login', function(client) {
|
|||||||
* `playerCount`
|
* `playerCount`
|
||||||
* `maxPlayers`
|
* `maxPlayers`
|
||||||
|
|
||||||
|
### 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
|
### Not Immediately Obvious Data Type Formats
|
||||||
|
|
||||||
#### entityMetadata
|
#### entityMetadata
|
||||||
|
97
index.js
97
index.js
@ -3,6 +3,7 @@ var EventEmitter = require('events').EventEmitter
|
|||||||
, assert = require('assert')
|
, assert = require('assert')
|
||||||
, ursa = require('ursa')
|
, ursa = require('ursa')
|
||||||
, crypto = require('crypto')
|
, crypto = require('crypto')
|
||||||
|
, bufferEqual = require('buffer-equal')
|
||||||
, superagent = require('superagent')
|
, superagent = require('superagent')
|
||||||
, protocol = require('./lib/protocol')
|
, protocol = require('./lib/protocol')
|
||||||
, Client = require('./lib/client')
|
, Client = require('./lib/client')
|
||||||
@ -35,6 +36,7 @@ function createServer(options) {
|
|||||||
var serverKey = ursa.generatePrivateKey(1024);
|
var serverKey = ursa.generatePrivateKey(1024);
|
||||||
|
|
||||||
var server = new Server(options);
|
var server = new Server(options);
|
||||||
|
server.onlineModeExceptions = {};
|
||||||
server.maxPlayers = maxPlayers;
|
server.maxPlayers = maxPlayers;
|
||||||
server.on("connection", function(client) {
|
server.on("connection", function(client) {
|
||||||
client.once(0xfe, onPing);
|
client.once(0xfe, onPing);
|
||||||
@ -101,8 +103,10 @@ function createServer(options) {
|
|||||||
|
|
||||||
function onHandshake(packet) {
|
function onHandshake(packet) {
|
||||||
client.username = packet.username;
|
client.username = packet.username;
|
||||||
|
var isException = !!server.onlineModeExceptions[client.username];
|
||||||
|
var needToVerify = (onlineMode && ! isException) || (! onlineMode && isException);
|
||||||
var serverId;
|
var serverId;
|
||||||
if (onlineMode) {
|
if (needToVerify) {
|
||||||
serverId = crypto.randomBytes(4).toString('hex');
|
serverId = crypto.randomBytes(4).toString('hex');
|
||||||
} else {
|
} else {
|
||||||
serverId = '-';
|
serverId = '-';
|
||||||
@ -128,50 +132,55 @@ function createServer(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onEncryptionKeyResponse(packet) {
|
function onEncryptionKeyResponse(packet) {
|
||||||
var success = client.verifyToken.toString("hex") === serverKey.decrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING).toString("hex");
|
var verifyToken = serverKey.decrypt(packet.verifyToken, undefined, undefined, ursa.RSA_PKCS1_PADDING);
|
||||||
if (success) {
|
if (! bufferEqual(client.verifyToken, verifyToken)) {
|
||||||
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 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)
|
|
||||||
});
|
|
||||||
client.encryptionEnabled = true;
|
|
||||||
if (! onlineMode) loginClient();
|
|
||||||
} else {
|
|
||||||
client.end('DidNotEncryptVerifyTokenProperly');
|
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);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ursa": "~0.8.0",
|
"ursa": "~0.8.0",
|
||||||
"superagent": "~0.10.0"
|
"superagent": "~0.10.0",
|
||||||
|
"buffer-equal": "0.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user