minecraft-protocol
Advanced tools
Comparing version 1.20.0 to 1.20.1
@@ -77,3 +77,3 @@ # Documentation | ||
* 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 | ||
@@ -96,3 +96,2 @@ * clientToken : generated if a password is given | ||
* 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 | ||
@@ -99,0 +98,0 @@ ## mc.Client(isServer,version,[customPackets]) |
# History | ||
## 1.20.1 | ||
* Temporarily revert token auth to fix a bug | ||
## 1.20.0 | ||
@@ -4,0 +8,0 @@ |
const mc = require('minecraft-protocol') | ||
if (process.argv.length !== 4) { | ||
console.log('Usage : node echo.js <host> <port> [<name>]') | ||
if (process.argv.length < 4 || process.argv.length > 6) { | ||
console.log('Usage : node echo.js <host> <port> [<name>] [<password>]') | ||
process.exit(1) | ||
@@ -11,7 +11,5 @@ } | ||
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) | ||
}) | ||
@@ -18,0 +16,0 @@ client.on('connect', function () { |
{ | ||
"name": "minecraft-protocol", | ||
"version": "1.20.0", | ||
"version": "1.20.1", | ||
"description": "Parse and serialize minecraft packets, plus authentication and encryption.", | ||
@@ -47,2 +47,3 @@ "main": "src/index.js", | ||
"aes-js": "^3.1.2", | ||
"yggdrasil": "^1.3.0", | ||
"buffer-equal": "^1.0.0", | ||
@@ -54,3 +55,2 @@ "debug": "^4.1.0", | ||
"minecraft-data": "^2.70.0", | ||
"minecraft-folder-path": "^1.1.0", | ||
"node-rsa": "^0.4.2", | ||
@@ -60,5 +60,4 @@ "prismarine-nbt": "^1.3.0", | ||
"readable-stream": "^3.0.6", | ||
"uuid-1345": "^1.0.1", | ||
"yggdrasil": "^1.4.0" | ||
"uuid-1345": "^1.0.1" | ||
} | ||
} |
const UUID = require('uuid-1345') | ||
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 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 | ||
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) { | ||
// make a request to get the case-correct username before connecting. | ||
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) { | ||
@@ -107,34 +25,2 @@ client.emit('error', err) | ||
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) { | ||
@@ -151,4 +37,3 @@ if (!skipValidation) { | ||
pass: options.password, | ||
token: clientToken, | ||
requestUser: true | ||
token: clientToken | ||
}, cb) | ||
@@ -155,0 +40,0 @@ } else { |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
13
7
167006
3517
- Removedminecraft-folder-path@^1.1.0
- Removedminecraft-folder-path@1.2.0(transitive)
Updatedyggdrasil@^1.3.0