diff --git a/.gitignore b/.gitignore index 9303c34..20c7123 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ -npm-debug.log \ No newline at end of file +npm-debug.log +__* \ No newline at end of file diff --git a/src/BatchPacket.js b/src/BatchPacket.js index 98de0c4..cdd9296 100644 --- a/src/BatchPacket.js +++ b/src/BatchPacket.js @@ -3,7 +3,7 @@ const Zlib = require('zlib'); const NETWORK_ID = 0xfe -// This is not a MCPE packet, it's a wrapper that contains compressed batched packets +// This is not a real MCPE packet, it's a wrapper that contains compressed/encrypted batched packets class BatchPacket { constructor(stream) { @@ -13,10 +13,6 @@ class BatchPacket { this.compressionLevel = 7 } - init() { - - } - decode() { // Read header const pid = this.stream.readByte(); @@ -47,7 +43,6 @@ class BatchPacket { addEncodedPacket(packet) { this.stream.writeUnsignedVarInt(packet.byteLength) this.stream.append(packet) - // this.payload = Buffer.concat([this.payload, stream.getBuffer()]); } getPackets() { diff --git a/src/auth/encryption.js b/src/auth/encryption.js index 9529fc0..a487f3e 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -1,10 +1,9 @@ const JWT = require('jsonwebtoken') const crypto = require('crypto') -const constants = require('./constants') const { Ber } = require('asn1') const ec_pem = require('ec-pem') -const SALT = 'ABC' +const SALT = '🧂' function Encrypt(client, options) { function startClientboundEncryption(publicKey) { @@ -48,25 +47,6 @@ function Encrypt(client, options) { client.startEncryption(initial) } - function startClientCiphers() { - - var decipher = crypto.createDecipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0, 16)) - - let customPackets = JSON.parse(JSON.stringify(require("../data/protocol"))) - - customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe_encrypted'] = 'restBuffer' - customPackets['types']['encapsulated_packet'][1][0]['type'][1]['mappings']['0xfe'] = 'mcpe_encrypted' - client.encapsulatedPacketParser.proto.addTypes(merge(require('raknet').protocol, customPackets).types) - - client.encryptionEnabled = true - - client.on("mcpe_encrypted", packet => { - decipher.write(packet); - }); - - client.cipher = crypto.createCipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0, 16)); - } - client.on('server.client_handshake', startClientboundEncryption) } diff --git a/src/auth/encrypt.js b/src/auth/tests/encrypt.js similarity index 100% rename from src/auth/encrypt.js rename to src/auth/tests/encrypt.js diff --git a/src/auth/encryptTest.js b/src/auth/tests/encryptTest.js similarity index 100% rename from src/auth/encryptTest.js rename to src/auth/tests/encryptTest.js diff --git a/src/auth/jwtTest.js b/src/auth/tests/jwtTest.js similarity index 100% rename from src/auth/jwtTest.js rename to src/auth/tests/jwtTest.js diff --git a/src/serverTest.js b/src/server.js similarity index 74% rename from src/serverTest.js rename to src/server.js index 226cd22..c4eaeb7 100644 --- a/src/serverTest.js +++ b/src/server.js @@ -1,4 +1,3 @@ -console.log('IMPORTING') const BinaryStream = require('@jsprismarine/jsbinaryutils').default const Listener = require('@jsprismarine/raknet/listener') const { ProtoDef, Parser, Serializer } = require('protodef') @@ -10,8 +9,7 @@ const { Encrypt } = require('./auth/encryption') const { decodeLoginJWT } = require('./auth/jwt') const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') -console.log('IMPORTED') -// const Zlib = require('zlib'); + var protocol = require('../data/newproto.json').types; @@ -123,6 +121,25 @@ class Player extends EventEmitter { } } + writeRaw(name, buffer) { // skip protodef serializaion + // temporary hard coded stuff + const batch = new BatchPacket() + if (name == 'biome_definition_list') { + // so we can send nbt straight from file without parsing + const stream = new BinaryStream() + stream.writeUnsignedVarInt(0x7a) + stream.append(buffer) + batch.addEncodedPacket(stream.getBuffer()) + // console.log('----- SENDING BIOME DEFINITIONS') + } + + if (this.encryptionEnabled) { + this.sendEncryptedBatch(batch) + } else { + this.sendDecryptedBatch(batch) + } + } + sendDecryptedBatch(batch) { const buf = batch.encode() // send to raknet @@ -130,7 +147,7 @@ class Player extends EventEmitter { sendPacket.reliability = 0; sendPacket.buffer = buf - this.connection.addEncapsulatedToQueue(sendPacket, 1) + this.connection.addEncapsulatedToQueue(sendPacket) this.connection.sendQueue() } @@ -268,21 +285,80 @@ class Server extends EventEmitter { } } +let CreativeItems = require('../data/creativeitems.json') +let NBT = require('prismarine-nbt') + let server = new Server({ }) server.create('0.0.0.0', 19130) +let ran = false + server.on('connect', ({ client }) => { /** @type {Player} */ client.on('join', () => { console.log('Client joined', client.getData()) + + // ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It + // sends a list of the resource packs it has and basic information on them like the version and description. client.write('resource_packs_info', { 'must_accept': false, 'has_scripts': false, 'behaviour_packs': [], 'texture_packs': [] }) + + client.once('resource_pack_client_response', (packet) => { + // ResourcePackStack is sent by the server to send the order in which resource packs and behaviour packs + // should be applied (and downloaded) by the client. + client.write('resource_pack_stack', { + 'must_accept': false, + 'behavior_packs': [], + 'resource_packs': [], + 'game_version': '', + 'experiments': [], + 'experiments_previously_toggled': false + }) + + client.once('resource_pack_client_response', async (packet) => { + if (ran === true) throw 'Already sent' + ran = true + let items = [] + let ids = 0 + for (var item of CreativeItems) { + let creativeitem = { runtime_id: items.length } + if (item.id != 0) { + const hasNbt = !!item.nbt_b64 + creativeitem.item = { + network_id: item.id, + auxiliary_value: item.damage || 0, + has_nbt: hasNbt|0, + nbt_version: 1, + blocking_tick: 0, + can_destroy: [], + can_place_on: [] + } + if (hasNbt) { + let nbtBuf = Buffer.from(item.nbt_b64, 'base64') + let { result } = await NBT.parse(nbtBuf, 'little') + creativeitem.item.nbt = result + } + } + items.push(creativeitem) + // console.log(creativeitem) + } + + console.log(items, ids) + + client.write('creative_content', { items }) + + setTimeout(() => { + const biomeDefs = fs.readFileSync('../data/biome_definitions.nbt') + client.writeRaw('biome_definition_list', biomeDefs) + }, 1000) + }) + }) }) }) \ No newline at end of file diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 491fe09..7aaee6b 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -130,14 +130,12 @@ function createDecryptor(client, iv) { } else { throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) } - // console.log('Calling cb') cb() } }) const inflator = new Transform({ transform(chunk, enc, cb) { - // console.log('INFLATING') Zlib.inflateRaw(chunk, { chunkSize: 1024 * 1024 * 2 }, (err, buf) => { if (err) throw err this.push(buf)