Revert "Add token authentication (#780)"

This reverts commit 0277091ddc.
This commits introduced a bug in offline mode.
We don't know yet how to fix it, so better revert first and fix later
This commit is contained in:
Romain Beaumont 2020-12-06 01:57:40 +01:00
parent 7be60af77d
commit 14c4886ac4
No known key found for this signature in database
GPG key ID: DB60E388B3BCF286
4 changed files with 11 additions and 130 deletions

View file

@ -74,7 +74,7 @@ Returns a `Client` instance and perform login.
`options` is an object containing the properties : `options` is an object containing the properties :
* username * username
* port : default to 25565 * port : default to 25565
* password : can be omitted (if the tokens and profilesFolder are also omitted then it tries to connect in offline mode) * password : can be omitted (if the tokens are also omitted then it tries to connect in offline mode)
* host : default to localhost * host : default to localhost
* clientToken : generated if a password is given * clientToken : generated if a password is given
* accessToken : generated if a password is given * accessToken : generated if a password is given
@ -92,7 +92,6 @@ Returns a `Client` instance and perform login.
* connect : a function taking the client as parameter and that should client.setSocket(socket) * 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) 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) * agent : a http agent that can be used to set proxy settings for yggdrasil authentication (see proxy-agent on npm)
* profilesFolder : the path to the folder that contains your `launcher_profiles.json`. defaults to your minecraft folder if it exists, otherwise the local directory. set to `false` to disable managing profiles
## mc.Client(isServer,version,[customPackets]) ## mc.Client(isServer,version,[customPackets])

View file

@ -1,17 +1,15 @@
const mc = require('minecraft-protocol') const mc = require('minecraft-protocol')
if (process.argv.length !== 4) { if (process.argv.length < 4 || process.argv.length > 6) {
console.log('Usage : node echo.js <host> <port> [<name>]') console.log('Usage : node echo.js <host> <port> [<name>] [<password>]')
process.exit(1) process.exit(1)
} }
const client = mc.createClient({ const client = mc.createClient({
host: process.argv[2], host: process.argv[2],
port: parseInt(process.argv[3]), port: parseInt(process.argv[3]),
username: process.argv[4] ? process.argv[4] : 'echo' username: process.argv[4] ? process.argv[4] : 'echo',
}) password: process.argv[5]
client.on('error', function (err) {
console.error(err)
}) })
client.on('connect', function () { client.on('connect', function () {

View file

@ -44,18 +44,17 @@
}, },
"dependencies": { "dependencies": {
"aes-js": "^3.1.2", "aes-js": "^3.1.2",
"yggdrasil": "^1.3.0",
"buffer-equal": "^1.0.0", "buffer-equal": "^1.0.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"endian-toggle": "^0.0.0", "endian-toggle": "^0.0.0",
"lodash.get": "^4.1.2", "lodash.get": "^4.1.2",
"lodash.merge": "^4.3.0", "lodash.merge": "^4.3.0",
"minecraft-data": "^2.70.0", "minecraft-data": "^2.70.0",
"minecraft-folder-path": "^1.1.0",
"node-rsa": "^0.4.2", "node-rsa": "^0.4.2",
"prismarine-nbt": "^1.3.0", "prismarine-nbt": "^1.3.0",
"protodef": "^1.8.0", "protodef": "^1.8.0",
"readable-stream": "^3.0.6", "readable-stream": "^3.0.6",
"uuid-1345": "^1.0.1", "uuid-1345": "^1.0.1"
"yggdrasil": "^1.4.0"
} }
} }

View file

@ -1,98 +1,16 @@
const UUID = require('uuid-1345') const UUID = require('uuid-1345')
const yggdrasil = require('yggdrasil') const yggdrasil = require('yggdrasil')
const fs = require('fs').promises
const mcDefaultFolderPath = require('minecraft-folder-path')
const path = require('path')
module.exports = async function (client, options) {
if (!options.profilesFolder && options.profilesFolder !== false) { // not defined, but not explicitly false. fallback to default
let mcFolderExists = true
try {
await fs.access(mcDefaultFolderPath)
} catch (ignoreErr) {
mcFolderExists = false
}
options.profilesFolder = mcFolderExists ? mcDefaultFolderPath : '.' // local folder if mc folder doesn't exist
}
module.exports = function (client, options) {
const yggdrasilClient = yggdrasil({ agent: options.agent, host: options.authServer || 'https://authserver.mojang.com' }) const yggdrasilClient = yggdrasil({ agent: options.agent, host: options.authServer || 'https://authserver.mojang.com' })
const clientToken = options.clientToken || (options.session && options.session.clientToken) || (options.profilesFolder && (await getLauncherProfiles()).clientToken) || UUID.v4().toString().replace(/-/g, '') const clientToken = options.clientToken || (options.session && options.session.clientToken) || UUID.v4().toString()
const skipValidation = false || options.skipValidation const skipValidation = false || options.skipValidation
options.accessToken = null options.accessToken = null
options.haveCredentials = options.password != null || (clientToken != null && options.session != null) || (options.profilesFolder && await hasProfileCredentials()) options.haveCredentials = options.password != null || (clientToken != null && options.session != null)
async function getLauncherProfiles () { // get launcher profiles
try {
return JSON.parse(await fs.readFile(path.join(options.profilesFolder, 'launcher_profiles.json'), 'utf8'))
} catch (err) {
await fs.mkdir(options.profilesFolder, { recursive: true })
await fs.writeFile(path.join(options.profilesFolder, 'launcher_profiles.json'), '{}')
return { authenticationDatabase: {} }
}
}
async function hasProfileCredentials () {
try {
const auths = await getLauncherProfiles()
const lowerUsername = options.username.toLowerCase()
return !!Object.keys(auths.authenticationDatabase).find(key =>
auths.authenticationDatabase[key].username.toLowerCase() === lowerUsername ||
Object.values(auths.authenticationDatabase[key].profiles)[0].displayName.toLowerCase() === lowerUsername
)
} catch (err) {
return false
}
}
if (options.haveCredentials) { if (options.haveCredentials) {
// make a request to get the case-correct username before connecting. // make a request to get the case-correct username before connecting.
const cb = function (err, session) { const cb = function (err, session) {
if (options.profilesFolder) {
getLauncherProfiles().then((auths) => {
try {
const lowerUsername = options.username.toLowerCase()
let profile = Object.keys(auths.authenticationDatabase).find(key =>
auths.authenticationDatabase[key].username.toLowerCase() === lowerUsername ||
Object.values(auths.authenticationDatabase[key].profiles)[0].displayName.toLowerCase() === lowerUsername
)
if (err) {
if (profile) { // profile is invalid, remove
delete auths.authenticationDatabase[profile]
}
} else { // successful login
if (!profile) {
profile = UUID.v4().toString().replace(/-/g, '') // create new profile
}
if (!auths.clientToken) {
auths.clientToken = clientToken
}
if (clientToken === auths.clientToken) { // only do something when we can save a new clienttoken or they match
const oldProfileObj = auths.authenticationDatabase[profile]
const newProfileObj = {
accessToken: session.accessToken,
profiles: {},
properties: oldProfileObj ? (oldProfileObj.properties || []) : [],
username: options.username
}
newProfileObj.profiles[session.selectedProfile.id] = {
displayName: session.selectedProfile.name
}
auths.authenticationDatabase[profile] = newProfileObj
}
}
} catch (ignoreErr) {
// again, silently fail, just don't save anything
}
fs.writeFile(path.join(options.profilesFolder, 'launcher_profiles.json'), JSON.stringify(auths, null, 2)).then(() => {}, (ignoreErr) => {
// console.warn("Couldn't save tokens:\n", err) // not any error, we just don't save the file
})
}, (ignoreErr) => {
// console.warn("Skipped saving tokens because of error\n", err) // not any error, we just don't save the file
})
}
if (err) { if (err) {
client.emit('error', err) client.emit('error', err)
} else { } else {
@ -104,38 +22,6 @@ module.exports = async function (client, options) {
} }
} }
if (!options.session && options.profilesFolder) {
try {
const auths = await getLauncherProfiles()
const lowerUsername = options.username.toLowerCase()
const profile = Object.keys(auths.authenticationDatabase).find(key =>
auths.authenticationDatabase[key].username.toLowerCase() === lowerUsername ||
Object.values(auths.authenticationDatabase[key].profiles)[0].displayName.toLowerCase() === lowerUsername
)
if (profile) {
const newUsername = auths.authenticationDatabase[profile].username
const uuid = Object.keys(auths.authenticationDatabase[profile].profiles)[0]
const displayName = auths.authenticationDatabase[profile].profiles[uuid].displayName
const newProfile = {
name: displayName,
id: uuid
}
options.session = {
accessToken: auths.authenticationDatabase[profile].accessToken,
clientToken: auths.clientToken,
selectedProfile: newProfile,
availableProfiles: [newProfile]
}
options.username = newUsername
}
} catch (ignoreErr) {
// skip the error :/
}
}
if (options.session) { if (options.session) {
if (!skipValidation) { if (!skipValidation) {
yggdrasilClient.validate(options.session.accessToken, function (err) { yggdrasilClient.validate(options.session.accessToken, function (err) {
@ -147,8 +33,7 @@ module.exports = async function (client, options) {
yggdrasilClient.auth({ yggdrasilClient.auth({
user: options.username, user: options.username,
pass: options.password, pass: options.password,
token: clientToken, token: clientToken
requestUser: true
}, cb) }, cb)
} else { } else {
cb(err, data) cb(err, data)