don't require both email and username. closes #32

This change breaks backwards compatibility.

`createClient` no longer takes an `email` argument. Instead, the
`username` argument is used to authenticate and determine the
case correct username.

There is a special case if you leave out the `password` argument.
In this case, `username` is used to connect directly to the server,
and you may get kicked if the server is in online mode.
This commit is contained in:
Andrew Kelley 2013-01-30 19:56:43 -05:00
parent 9c12b6d3d3
commit df3f95e1ff
4 changed files with 49 additions and 49 deletions

View file

@ -34,11 +34,10 @@ no more. If you want a higher-level API with which to write bots, see
```js
var mc = require('minecraft-protocol');
var client = mc.createClient({
host: "localhost", // optional
port: 25565, // optional
username: "player",
email: "email@example.com", // email and password are required only for
password: "12345678", // online-mode=true servers
host: "localhost", // optional
port: 25565, // optional
username: "email@example.com",
password: "12345678",
});
client.on(0x03, function(packet) {
// Listen for chat messages and echo them back.
@ -49,6 +48,8 @@ client.on(0x03, function(packet) {
});
```
If the server is in offline mode, you may leave out the `password` option.
### Hello World server example
```js
@ -128,7 +129,7 @@ correct data type.
* Ensure your system has the `java` executable in `PATH`.
* Download the appropriate version of `minecraft_server.jar`.
* `MC_SERVER_JAR=path/to/minecraft_server.jar MC_USERNAME=username MC_EMAIL=email@example.com MC_PASSWORD=password npm test`
* `MC_SERVER_JAR=path/to/minecraft_server.jar MC_EMAIL=email@example.com MC_PASSWORD=password npm test`
### Test Coverage

View file

@ -1,9 +1,7 @@
var mc = require('../');
var client = mc.createClient({
username: process.env.MC_USERNAME,
email: process.env.MC_EMAIL,
password: process.env.MC_PASSWORD,
verbose: true,
});
client.on('connect', function() {
console.info("connected");

View file

@ -193,27 +193,43 @@ function createClient(options) {
var port = options.port || 25565;
var host = options.host || 'localhost';
assert.ok(options.username, "username is required");
var haveCredentials = typeof options.password !== "undefined";
var haveCredentials = options.password != null;
var keepAlive = options.keepAlive == null ? true : options.keepAlive;
var email = options.email || options.username;
var password = options.password;
var client = new Client(false);
client.username = options.username;
client.on('connect', function() {
client.on('connect', onConnect);
if (keepAlive) client.on(0x00, onKeepAlive);
client.once(0xFC, onEncryptionKeyResponse);
client.once(0xFD, onEncryptionKeyRequest);
if (haveCredentials) {
// make a request to get the case-correct username before connecting.
getLoginSession(options.username, options.password, function(err, session) {
if (err) {
client.emit('error', err);
} else {
client.session = session;
client.username = session.username;
client.emit('session');
client.connect(port, host);
}
});
} else {
// assume the server is in offline mode and just go for it.
client.username = options.username;
client.connect(port, host);
}
return client;
function onConnect() {
client.write(0x02, {
protocolVersion: protocol.version,
username: client.username,
serverHost: host,
serverPort: port,
});
});
if (keepAlive) client.on(0x00, onKeepAlive);
client.once(0xFC, onEncryptionKeyResponse);
client.once(0xFD, onEncryptionKeyRequest);
client.connect(port, host);
return client;
}
function onKeepAlive(packet) {
client.write(0x00, {
@ -222,30 +238,21 @@ function createClient(options) {
}
function onEncryptionKeyRequest(packet) {
var batch = new Batch();
var hash;
if (haveCredentials) {
hash = crypto.createHash('sha1');
hash.update(packet.serverId);
batch.push(function(cb) { getLoginSession(email, password, cb); });
}
batch.push(function(cb) { crypto.randomBytes(16, cb); });
batch.end(function (err, results) {
crypto.randomBytes(16, gotSharedSecret);
function gotSharedSecret(err, sharedSecret) {
if (err) {
client.emit('error', err);
client.end();
return
}
var sharedSecret;
var hash = crypto.createHash('sha1');
hash.update(packet.serverId);
if (haveCredentials) {
client.session = results[0];
client.username = client.session.username;
client.emit('session');
sharedSecret = results[1];
joinServerRequest(onJoinServerResponse);
} else {
sharedSecret = results[0];
sendEncryptionKeyResponse();
}
@ -298,7 +305,7 @@ function createClient(options) {
verifyToken: encryptedVerifyTokenBuffer,
});
}
});
}
}
function onEncryptionKeyResponse(packet) {

View file

@ -264,7 +264,6 @@ describe("client", function() {
startServer({ 'online-mode': 'true' }, function() {
var client = mc.createClient({
username: process.env.MC_USERNAME,
email: process.env.MC_EMAIL,
password: process.env.MC_PASSWORD,
});
mcServer.on('line', function(line) {
@ -299,12 +298,12 @@ describe("client", function() {
it("connects successfully - offline mode", function(done) {
startServer({ 'online-mode': 'false' }, function() {
var client = mc.createClient({
username: process.env.MC_USERNAME,
username: 'Player',
});
mcServer.on('line', function(line) {
var match = line.match(/\[INFO\] <(.+?)> (.+)$/);
if (! match) return;
assert.strictEqual(match[1], process.env.MC_USERNAME);
assert.strictEqual(match[1], 'Player');
assert.strictEqual(match[2], "hello everyone; I have logged in.");
mcServer.stdin.write("say hello\n");
});
@ -322,7 +321,7 @@ describe("client", function() {
chatCount += 1;
assert.ok(chatCount <= 2);
if (chatCount === 1) {
assert.strictEqual(packet.message, "<" + process.env.MC_USERNAME + ">" + " hello everyone; I have logged in.");
assert.strictEqual(packet.message, "<Player>" + " hello everyone; I have logged in.");
} else if (chatCount === 2) {
assert.strictEqual(packet.message, "[Server] hello");
done();
@ -333,7 +332,7 @@ describe("client", function() {
it("gets kicked when no credentials supplied in online mode", function(done) {
startServer({ 'online-mode': 'true' }, function() {
var client = mc.createClient({
username: process.env.MC_USERNAME,
username: 'Player',
});
var gotKicked = false;
client.on(0xff, function(packet) {
@ -349,7 +348,7 @@ describe("client", function() {
it("does not crash for " + SURVIVE_TIME + "ms", function(done) {
startServer({ 'online-mode': 'false' }, function() {
var client = mc.createClient({
username: process.env.MC_USERNAME,
username: 'Player',
});
client.on(0x01, function(packet) {
client.write(0x03, {
@ -357,7 +356,7 @@ describe("client", function() {
});
});
client.on(0x03, function(packet) {
assert.strictEqual(packet.message, "<" + process.env.MC_USERNAME + ">" + " hello everyone; I have logged in.");
assert.strictEqual(packet.message, "<Player>" + " hello everyone; I have logged in.");
setTimeout(function() {
done();
}, SURVIVE_TIME);
@ -533,7 +532,7 @@ describe("mc-server", function() {
});
it("kicks clients when invalid credentials", function(done) {
var server = mc.createServer();
var count = 5;
var count = 4;
server.on('connection', function(client) {
client.on('end', function(reason) {
resolve();
@ -547,11 +546,6 @@ describe("mc-server", function() {
resolve();
var client = mc.createClient({
username: 'lalalal',
password: "this is wrong",
});
client.on('error', function(err) {
assert.strictEqual(err.code, 'ELOGIN400');
resolve();
});
client.on('end', function() {
resolve();