Pass through http agent option to yggdrasil for proxy support (#676)

* initialize yggdrasil with agent option if it exists

* standardjs

* move require statements to the top

* add agent option to docs and ts type information
also removed useless typescript import and moved class fields from wrong class to the correct one

* update proxy examples and add http agents for proxying yggdrasil

* update to agent supporting yggdrasil version
This commit is contained in:
Idan Horowitz 2020-02-11 13:31:24 +02:00 committed by GitHub
parent db1c7c31e4
commit 54380a3cb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 39 additions and 24 deletions

View file

@ -21,10 +21,8 @@ automatically logged in and validated against mojang's auth.
* customPackets (optional) : an object index by version/state/direction/name, see client_custom_packet for an example
* errorHandler : A way to override the default error handler for client errors. A function that takes a Client and an error.
The default kicks the client.
* stream : a stream to use as connection
* connect : a function taking the client as parameter and that should client.setSocket(socket)
and client.emit('connect') when appropriate (see the proxy examples for an example of use)
* hideErrors : do not display errors, default to false
* agent : a http agent that can be used to set proxy settings for yggdrasil authentication confirmation (see proxy-agent on npm)
## mc.Server(version,[customPackets])
@ -85,6 +83,10 @@ Returns a `Client` instance and perform login.
* customPackets (optional) : an object index by version/state/direction/name, see client_custom_packet for an example
* hideErrors : do not display errors, default to false
* skipValidation : do not try to validate given session, defaults to false
* stream : a stream to use as connection
* connect : a function taking the client as parameter and that should client.setSocket(socket)
and client.emit('connect') when appropriate (see the proxy examples for an example of use)
* agent : a http agent that can be used to set proxy settings for yggdrasil authentication (see proxy-agent on npm)
## mc.Client(isServer,version,[customPackets])

View file

@ -1,5 +1,6 @@
const mc = require('minecraft-protocol')
const Http = require('http')
const ProxyAgent = require('proxy-agent')
if (process.argv.length < 6 || process.argv.length > 8) {
console.log('Usage : node client_http_proxy.js <host> <port> <proxyHost> <proxyPort> [<name>] [<password>]')
@ -19,11 +20,12 @@ const client = mc.createClient({
})
req.end()
req.on('connect', function (res, stream) {
req.on('connect', (res, stream) => {
client.setSocket(stream)
client.emit('connect')
})
},
agent: new ProxyAgent({ protocol: 'http', host: proxyHost, port: proxyPort }),
username: process.argv[6] ? process.argv[6] : 'echo',
password: process.argv[7]
})

View file

@ -2,6 +2,8 @@
"name": "node-minecraft-protocol-example",
"version": "0.0.0",
"private": true,
"dependencies": {},
"dependencies": {
"proxy-agent": "^3.1.1"
},
"description": "A node-minecraft-protocol example"
}

View file

@ -1,5 +1,6 @@
const mc = require('minecraft-protocol')
const socks = require('socks')
const socks = require('socks').SocksClient
const ProxyAgent = require('proxy-agent')
if (process.argv.length < 6 || process.argv.length > 8) {
console.log('Usage : node client_socks_proxy.js <host> <port> <proxyHost> <proxyPort> [<name>] [<password>]')
@ -13,24 +14,26 @@ const client = mc.createClient({
connect: client => {
socks.createConnection({
proxy: {
ipaddress: proxyHost,
host: proxyHost,
port: proxyPort,
type: 5
},
target: {
command: 'connect',
destination: {
host: process.argv[2],
port: parseInt(process.argv[3])
}
}, function (err, socket) {
}, (err, info) => {
if (err) {
console.log(err)
return
}
client.setSocket(socket)
client.setSocket(info.socket)
client.emit('connect')
})
},
agent: new ProxyAgent({ protocol: 'socks5', host: proxyHost, port: proxyPort }),
username: process.argv[6] ? process.argv[6] : 'echo',
password: process.argv[7]
})

View file

@ -3,7 +3,8 @@
"version": "0.0.0",
"private": true,
"dependencies": {
"socks": "^1.1.10"
"proxy-agent": "^3.1.1",
"socks": "^2.3.3"
},
"description": "A node-minecraft-protocol example"
}

View file

@ -42,7 +42,7 @@
"standard": "^14.0.0"
},
"dependencies": {
"yggdrasil": "^1.2.0",
"yggdrasil": "^1.3.0",
"buffer-equal": "^1.0.0",
"debug": "^4.1.0",
"endian-toggle": "^0.0.0",

View file

@ -1,7 +1,8 @@
const yggdrasil = require('yggdrasil')({})
const UUID = require('uuid-1345')
const yggdrasil = require('yggdrasil')
module.exports = function (client, options) {
const yggdrasilClient = yggdrasil({ agent: options.agent })
const clientToken = options.clientToken || (options.session && options.session.clientToken) || UUID.v4().toString()
const skipValidation = false || options.skipValidation
options.accessToken = null
@ -23,13 +24,13 @@ module.exports = function (client, options) {
if (options.session) {
if (!skipValidation) {
yggdrasil.validate(options.session.accessToken, function (err) {
yggdrasilClient.validate(options.session.accessToken, function (err) {
if (!err) { cb(null, options.session) } else {
yggdrasil.refresh(options.session.accessToken, options.session.clientToken, function (err, accessToken, data) {
yggdrasilClient.refresh(options.session.accessToken, options.session.clientToken, function (err, accessToken, data) {
if (!err) {
cb(null, data)
} else if (options.username && options.password) {
yggdrasil.auth({
yggdrasilClient.auth({
user: options.username,
pass: options.password,
token: clientToken
@ -45,7 +46,7 @@ module.exports = function (client, options) {
cb(null, options.session)
}
} else {
yggdrasil.auth({
yggdrasilClient.auth({
user: options.username,
pass: options.password,
token: clientToken

View file

@ -1,10 +1,11 @@
'use strict'
const crypto = require('crypto')
const yggserver = require('yggdrasil').server({})
const debug = require('debug')('minecraft-protocol')
const yggdrasil = require('yggdrasil')
module.exports = function (client, options) {
const yggdrasilServer = yggdrasil.server({ agent: options.agent })
client.once('encryption_begin', onEncryptionKeyRequest)
function onEncryptionKeyRequest (packet) {
@ -36,7 +37,7 @@ module.exports = function (client, options) {
}
function joinServerRequest (cb) {
yggserver.join(options.accessToken, client.session.selectedProfile.id,
yggdrasilServer.join(options.accessToken, client.session.selectedProfile.id,
packet.serverId, sharedSecret, packet.publicKey, cb)
}

8
src/index.d.ts vendored
View file

@ -3,7 +3,7 @@
import { EventEmitter } from 'events';
import { Socket } from 'net'
import * as Stream from 'stream'
import { on } from 'cluster';
import { Agent } from 'http'
declare module 'minecraft-protocol' {
export class Client extends EventEmitter {
@ -46,6 +46,9 @@ declare module 'minecraft-protocol' {
username: string
version?: string
skipValidation?: boolean
stream?: Stream
connect?: (client: Client) => void
agent?: Agent
}
export class Server extends EventEmitter {
@ -73,11 +76,10 @@ declare module 'minecraft-protocol' {
maxPlayers?: number
motd?: string
port?: number
stream?: Stream
version?: string
beforePing?: (response: any, client: Client, callback?: (result: any) => any) => any
connect?: (client: Client) => void
errorHandler?: (client: Client, error: Error) => void
agent?: Agent
}
export interface SerializerOptions {

View file

@ -1,11 +1,12 @@
const yggserver = require('yggdrasil').server({})
const UUID = require('uuid-1345')
const bufferEqual = require('buffer-equal')
const crypto = require('crypto')
const pluginChannels = require('../client/pluginChannels')
const states = require('../states')
const yggdrasil = require('yggdrasil')
module.exports = function (client, server, options) {
const yggdrasilServer = yggdrasil.server({ agent: options.agent })
const {
'online-mode': onlineMode = true,
kickTimeout = 30 * 1000,
@ -74,7 +75,7 @@ module.exports = function (client, server, options) {
nextStep()
function verifyUsername () {
yggserver.hasJoined(client.username, serverId, sharedSecret, client.publicKey, function (err, profile) {
yggdrasilServer.hasJoined(client.username, serverId, sharedSecret, client.publicKey, function (err, profile) {
if (err) {
client.end('Failed to verify username!')
return