mirror of
https://github.com/PrismarineJS/node-minecraft-protocol.git
synced 2024-11-27 17:55:45 -05:00
Fix chat previews not working (#1054)
* Fix chat previews not working * Update signMessage to account for chat previews * Fix lint * Fix signMessage function * Server side chat preview verification * Fix default value overriding provided value * Only sign previews when they are formatted * Sign undecorated messages when text is changed * Update docs
This commit is contained in:
parent
28093fb1fb
commit
2a5ec378c4
4 changed files with 24 additions and 5 deletions
|
@ -32,6 +32,7 @@ automatically logged in and validated against mojang's auth.
|
|||
* agent : a http agent that can be used to set proxy settings for yggdrasil authentication confirmation (see proxy-agent on npm)
|
||||
* validateChannelProtocol (optional) : whether or not to enable protocol validation for custom protocols using plugin channels for the connected clients. Defaults to true
|
||||
* enforceSecureProfile (optional) : Kick clients that do not have chat signing keys from Mojang (1.19+)
|
||||
* generatePreview (optional) : Function to generate chat previews. Takes the raw message string and should return the message preview as a string. (1.19-1.19.2)
|
||||
|
||||
## mc.Server(version,[customPackets])
|
||||
|
||||
|
|
|
@ -2,6 +2,20 @@ const crypto = require('crypto')
|
|||
const concat = require('../transforms/binaryStream').concat
|
||||
const messageExpireTime = 420000 // 7 minutes (ms)
|
||||
|
||||
function isFormatted (message) {
|
||||
// This should match the ChatComponent.isDecorated function from Vanilla
|
||||
try {
|
||||
const comp = JSON.parse(message)
|
||||
for (const key in comp) {
|
||||
if (key !== 'text') return true
|
||||
}
|
||||
if (comp.text && comp.text !== message) return true
|
||||
return false
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function (client, options) {
|
||||
const mcData = require('minecraft-data')(client.version)
|
||||
client._players = {}
|
||||
|
@ -166,7 +180,7 @@ module.exports = function (client, options) {
|
|||
message,
|
||||
timestamp: options.timestamp,
|
||||
salt: options.salt,
|
||||
signature: client.profileKeys ? client.signMessage(message, options.timestamp, options.salt) : Buffer.alloc(0),
|
||||
signature: client.profileKeys ? client.signMessage(message, options.timestamp, options.salt, options.preview) : Buffer.alloc(0),
|
||||
signedPreview: options.didPreview,
|
||||
previousMessages: client._lastSeenMessages.map((e) => ({
|
||||
messageSender: e.sender,
|
||||
|
@ -186,14 +200,14 @@ module.exports = function (client, options) {
|
|||
}
|
||||
|
||||
client.on('chat_preview', (packet) => {
|
||||
if (pendingChatRequest && pendingChatRequest.id === packet.query) {
|
||||
client._signedChat(packet.message, { ...pendingChatRequest.options, skipPreview: true, didPreview: true })
|
||||
if (pendingChatRequest && pendingChatRequest.id === packet.queryId) {
|
||||
client._signedChat(pendingChatRequest.message, { ...pendingChatRequest.options, skipPreview: true, didPreview: true, preview: isFormatted(packet.message) ? packet.message : undefined })
|
||||
pendingChatRequest = null
|
||||
}
|
||||
})
|
||||
|
||||
// Signing methods
|
||||
client.signMessage = (message, timestamp, salt = 0) => {
|
||||
client.signMessage = (message, timestamp, salt = 0, preview) => {
|
||||
if (!client.profileKeys) throw Error("Can't sign message without profile keys, please set valid auth mode")
|
||||
|
||||
if (mcData.supportFeature('chainedChatWithHashing')) {
|
||||
|
@ -209,6 +223,7 @@ module.exports = function (client, options) {
|
|||
} else {
|
||||
const hash = crypto.createHash('sha256')
|
||||
hash.update(concat('i64', salt, 'i64', timestamp / 1000n, 'pstring', message, 'i8', 70))
|
||||
if (preview) hash.update(preview)
|
||||
for (const previousMessage of client._lastSeenMessages) {
|
||||
hash.update(concat('i8', 70, 'UUID', previousMessage.sender))
|
||||
hash.update(previousMessage.signature)
|
||||
|
|
2
src/index.d.ts
vendored
2
src/index.d.ts
vendored
|
@ -36,7 +36,7 @@ declare module 'minecraft-protocol' {
|
|||
registerChannel(name: string, typeDefinition: any, custom?: boolean): void
|
||||
unregisterChannel(name: string): void
|
||||
writeChannel(channel: any, params: any): void
|
||||
signMessage(message: string, timestamp: BigInt, salt?: number): Buffer
|
||||
signMessage(message: string, timestamp: BigInt, salt?: number, preview?: string): Buffer
|
||||
verifyMessage(publicKey: Buffer | KeyObject, packet: object): boolean
|
||||
reportPlayer(uuid: string, reason: 'FALSE_REPORTING' | 'HATE_SPEECH' | 'TERRORISM_OR_VIOLENT_EXTREMISM' | 'CHILD_SEXUAL_EXPLOITATION_OR_ABUSE' | 'IMMINENT_HARM' | 'NON_CONSENSUAL_INTIMATE_IMAGERY' | 'HARASSMENT_OR_BULLYING' | 'DEFAMATION_IMPERSONATION_FALSE_INFORMATION' | 'SELF_HARM_OR_SUICIDE' | 'ALCOHOL_TOBACCO_DRUGS', signatures: Buffer[], comment?: string): Promise<true>
|
||||
on(event: 'error', listener: (error: Error) => PromiseLike): this
|
||||
|
|
|
@ -42,6 +42,8 @@ module.exports = function (client, server, options) {
|
|||
const raise = (translatableError) => client.end(translatableError, JSON.stringify({ translate: translatableError }))
|
||||
const pending = new Pending()
|
||||
|
||||
if (!options.generatePreview) options.generatePreview = message => message
|
||||
|
||||
function validateMessageChain (packet) {
|
||||
try {
|
||||
validateLastMessages(pending, packet.previousMessages, packet.lastRejectedMessage)
|
||||
|
@ -92,6 +94,7 @@ module.exports = function (client, server, options) {
|
|||
// Player Chat
|
||||
const hash = crypto.createHash('sha256')
|
||||
hash.update(concat('i64', packet.salt, 'i64', packet.timestamp / 1000n, 'pstring', packet.message, 'i8', 70))
|
||||
if (packet.signedPreview) hash.update(options.generatePreview(packet.message))
|
||||
for (const { messageSender, messageSignature } of packet.previousMessages) {
|
||||
hash.update(concat('i8', 70, 'UUID', messageSender))
|
||||
hash.update(messageSignature)
|
||||
|
|
Loading…
Reference in a new issue