server player extends connection
This commit is contained in:
parent
73d4dd1325
commit
da85b80c59
4 changed files with 148 additions and 114 deletions
|
|
@ -80,7 +80,18 @@ function decodeLoginJWT(authTokens, skinTokens) {
|
|||
return { key, userData: data, skinData }
|
||||
}
|
||||
|
||||
function test() {
|
||||
function encodeLoginJWT(localChain, mojangChain) {
|
||||
const chains = []
|
||||
chains.push(localChain)
|
||||
for (const chain of mojangChain) {
|
||||
chains.push(chain)
|
||||
}
|
||||
return chains
|
||||
}
|
||||
|
||||
module.exports = { encodeLoginJWT, decodeLoginJWT }
|
||||
|
||||
function testServer() {
|
||||
const loginPacket = require('./login.json')
|
||||
|
||||
// console.log(loginPacket)
|
||||
|
|
@ -95,10 +106,7 @@ function test() {
|
|||
}
|
||||
|
||||
console.log('Authed')
|
||||
|
||||
// console.log(loginPacket)
|
||||
}
|
||||
|
||||
module.exports = { decodeLoginJWT }
|
||||
|
||||
// test()
|
||||
// testServer()
|
||||
|
|
@ -4,15 +4,19 @@ const { Ber } = require('asn1')
|
|||
const ec_pem = require('ec-pem')
|
||||
|
||||
const SALT = '🧂'
|
||||
const curve = 'secp384r1'
|
||||
|
||||
function Encrypt(client, options) {
|
||||
client.ecdhKeyPair = crypto.createECDH(curve)
|
||||
client.ecdhKeyPair.generateKeys()
|
||||
|
||||
createClientChain(client)
|
||||
|
||||
function startClientboundEncryption(publicKey) {
|
||||
console.warn('[encrypt] Pub key base64: ', publicKey)
|
||||
const pubKeyBuf = readX509PublicKey(publicKey.key)
|
||||
|
||||
const curve = 'secp384r1'
|
||||
const alice = crypto.createECDH(curve)
|
||||
alice.generateKeys()
|
||||
const alice = client.ecdhKeyPair
|
||||
const alicePEM = ec_pem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125
|
||||
const alicePEMPrivate = alicePEM.encodePrivateKey()
|
||||
// Shared secret from bob's public key + our private key
|
||||
|
|
@ -47,9 +51,27 @@ function Encrypt(client, options) {
|
|||
client.startEncryption(initial)
|
||||
}
|
||||
|
||||
function startServerboundEncryption() {
|
||||
|
||||
}
|
||||
|
||||
client.on('server.client_handshake', startClientboundEncryption)
|
||||
}
|
||||
|
||||
function createClientChain(client) {
|
||||
const alice = client.ecdhKeyPair
|
||||
const alicePEM = ec_pem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125
|
||||
const alicePEMPrivate = alicePEM.encodePrivateKey()
|
||||
const x509 = writeX509PublicKey(alice.getPublicKey())
|
||||
|
||||
const token = JWT.sign({
|
||||
salt: toBase64(SALT),
|
||||
signedToken: alice.getPublicKey('base64')
|
||||
}, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: x509 } })
|
||||
|
||||
client.clientChain = token
|
||||
}
|
||||
|
||||
function toBase64(string) {
|
||||
return Buffer.from(string).toString('base64')
|
||||
}
|
||||
|
|
|
|||
107
src/connection.js
Normal file
107
src/connection.js
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
const BinaryStream = require('@jsprismarine/jsbinaryutils').default
|
||||
const BatchPacket = require('./BatchPacket')
|
||||
const cipher = require('./transforms/encryption')
|
||||
const { EventEmitter } = require('events')
|
||||
const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet')
|
||||
|
||||
|
||||
class Connection extends EventEmitter {
|
||||
startEncryption(iv) {
|
||||
this.encryptionEnabled = true
|
||||
|
||||
this.decrypt = cipher.createDecryptor(this, iv)
|
||||
this.encrypt = cipher.createEncryptor(this, iv)
|
||||
}
|
||||
|
||||
write(name, params) { // TODO: Batch
|
||||
console.log('Need to encode', name, params)
|
||||
const batch = new BatchPacket()
|
||||
const packet = this.server.serializer.createPacketBuffer({ name, params })
|
||||
batch.addEncodedPacket(packet)
|
||||
|
||||
if (this.encryptionEnabled) {
|
||||
this.sendEncryptedBatch(batch)
|
||||
} else {
|
||||
this.sendDecryptedBatch(batch)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
const sendPacket = new EncapsulatedPacket();
|
||||
sendPacket.reliability = 0;
|
||||
sendPacket.buffer = buf
|
||||
|
||||
this.connection.addEncapsulatedToQueue(sendPacket)
|
||||
this.connection.sendQueue()
|
||||
}
|
||||
|
||||
sendEncryptedBatch(batch) {
|
||||
const buf = batch.stream.getBuffer()
|
||||
console.log('Sending encrypted batch', batch)
|
||||
this.encrypt(buf)
|
||||
}
|
||||
|
||||
// These are callbacks called from encryption.js
|
||||
onEncryptedPacket = (buf) => {
|
||||
console.log('ENC BUF', buf)
|
||||
const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header
|
||||
const sendPacket = new EncapsulatedPacket();
|
||||
sendPacket.reliability = 0
|
||||
sendPacket.buffer = packet
|
||||
console.log('Sending wrapped encrypted batch', packet)
|
||||
this.connection.addEncapsulatedToQueue(sendPacket)
|
||||
}
|
||||
|
||||
onDecryptedPacket = (buf) => {
|
||||
console.log('Decrypted', buf)
|
||||
|
||||
const stream = new BinaryStream(buf)
|
||||
const packets = BatchPacket.getPackets(stream)
|
||||
|
||||
for (const packet of packets) {
|
||||
this.readPacket(packet)
|
||||
}
|
||||
}
|
||||
|
||||
handle(buffer) { // handle encapsulated
|
||||
if (buffer[0] == 0xfe) { // wrapper
|
||||
|
||||
if (this.encryptionEnabled) {
|
||||
// console.log('READING ENCRYPTED PACKET', buffer)
|
||||
this.decrypt(buffer.slice(1))
|
||||
} else {
|
||||
const stream = new BinaryStream(buffer)
|
||||
const batch = new BatchPacket(stream)
|
||||
batch.decode()
|
||||
const packets = batch.getPackets()
|
||||
console.log('Reading ', packets.length, 'packets')
|
||||
for (var packet of packets) {
|
||||
this.readPacket(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Connection }
|
||||
109
src/server.js
109
src/server.js
|
|
@ -1,14 +1,9 @@
|
|||
const BinaryStream = require('@jsprismarine/jsbinaryutils').default
|
||||
const Listener = require('@jsprismarine/raknet/listener')
|
||||
const { ProtoDef, Parser, Serializer } = require('protodef')
|
||||
const BatchPacket = require('./BatchPacket')
|
||||
const { EventEmitter } = require('events')
|
||||
const cipher = require('./transforms/encryption')
|
||||
const { Encrypt } = require('./auth/encryption')
|
||||
|
||||
const { decodeLoginJWT } = require('./auth/jwt')
|
||||
const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet')
|
||||
|
||||
const { decodeLoginJWT } = require('./auth/chains')
|
||||
const { Connection } = require('./connection')
|
||||
|
||||
var protocol = require('../data/newproto.json').types;
|
||||
|
||||
|
|
@ -41,7 +36,7 @@ const PLAY_STATUS = {
|
|||
'LoginFailedServerFull': 7
|
||||
}
|
||||
|
||||
class Player extends EventEmitter {
|
||||
class Player extends Connection {
|
||||
constructor(server, connection, options) {
|
||||
super()
|
||||
this.server = server
|
||||
|
|
@ -100,84 +95,6 @@ class Player extends EventEmitter {
|
|||
this.emit('join')
|
||||
}
|
||||
|
||||
startEncryption(iv) {
|
||||
this.encryptionEnabled = true
|
||||
|
||||
this.decrypt = cipher.createDecryptor(this, iv)
|
||||
this.encrypt = cipher.createEncryptor(this, iv)
|
||||
}
|
||||
|
||||
write(name, params) { // TODO: Batch
|
||||
console.log('Need to encode', name, params)
|
||||
const batch = new BatchPacket()
|
||||
const packet = this.server.serializer.createPacketBuffer({ name, params })
|
||||
batch.addEncodedPacket(packet)
|
||||
|
||||
if (this.encryptionEnabled) {
|
||||
this.sendEncryptedBatch(batch)
|
||||
} else {
|
||||
this.sendDecryptedBatch(batch)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
const sendPacket = new EncapsulatedPacket();
|
||||
sendPacket.reliability = 0;
|
||||
sendPacket.buffer = buf
|
||||
|
||||
this.connection.addEncapsulatedToQueue(sendPacket)
|
||||
this.connection.sendQueue()
|
||||
}
|
||||
|
||||
sendEncryptedBatch(batch) {
|
||||
const buf = batch.stream.getBuffer()
|
||||
console.log('Sending encrypted batch', batch)
|
||||
this.encrypt(buf)
|
||||
}
|
||||
|
||||
// These are callbacks called from encryption.js
|
||||
onEncryptedPacket = (buf) => {
|
||||
console.log('ENC BUF', buf)
|
||||
const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header
|
||||
const sendPacket = new EncapsulatedPacket();
|
||||
sendPacket.reliability = 0
|
||||
sendPacket.buffer = packet
|
||||
console.log('Sending wrapped encrypted batch', packet)
|
||||
this.connection.addEncapsulatedToQueue(sendPacket)
|
||||
}
|
||||
|
||||
onDecryptedPacket = (buf) => {
|
||||
console.log('Decrypted', buf)
|
||||
|
||||
const stream = new BinaryStream(buf)
|
||||
const packets = BatchPacket.getPackets(stream)
|
||||
|
||||
for (const packet of packets) {
|
||||
this.readPacket(packet)
|
||||
}
|
||||
}
|
||||
|
||||
readPacket(packet) {
|
||||
console.log('packet', packet)
|
||||
const des = this.server.deserializer.parsePacketBuffer(packet)
|
||||
|
|
@ -193,26 +110,6 @@ class Player extends EventEmitter {
|
|||
console.log('ignoring, unhandled')
|
||||
}
|
||||
this.emit(des.data.name, des.data.params)
|
||||
|
||||
}
|
||||
|
||||
handle(buffer) { // handle encapsulated
|
||||
if (buffer[0] == 0xfe) { // wrapper
|
||||
|
||||
if (this.encryptionEnabled) {
|
||||
// console.log('READING ENCRYPTED PACKET', buffer)
|
||||
this.decrypt(buffer.slice(1))
|
||||
} else {
|
||||
const stream = new BinaryStream(buffer)
|
||||
const batch = new BatchPacket(stream)
|
||||
batch.decode()
|
||||
const packets = batch.getPackets()
|
||||
console.log('Reading ', packets.length, 'packets')
|
||||
for (var packet of packets) {
|
||||
this.readPacket(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue