From df3f95e1ff122a29a3aa65f75e8f40a6bd1d3948 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Jan 2013 19:56:43 -0500 Subject: [PATCH] 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. --- README.md | 13 +++++---- examples/client_echo.js | 2 -- index.js | 63 +++++++++++++++++++++++------------------ test/test.js | 20 +++++-------- 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 0963c9f..10a149b 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/examples/client_echo.js b/examples/client_echo.js index 1b2b05f..e456f9e 100644 --- a/examples/client_echo.js +++ b/examples/client_echo.js @@ -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"); diff --git a/index.js b/index.js index f006c01..6f8500e 100644 --- a/index.js +++ b/index.js @@ -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) { diff --git a/test/test.js b/test/test.js index 63727fc..eda9d47 100644 --- a/test/test.js +++ b/test/test.js @@ -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, "" + " 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, "" + " 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();