reapply on master (#1067)

This commit is contained in:
extremeheat 2023-05-28 04:28:56 -04:00 committed by GitHub
parent d9e37e3d76
commit d643d40415
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 12 deletions

View file

@ -266,9 +266,9 @@ Called when an error occurs within the client. Takes an Error as parameter.
### `playerChat` event
Called when a chat message from another player arrives. The emitted object contains:
* formattedMessage -- the chat message preformatted, if done on server side
* plainMessage -- the chat message without formatting (for example no `<username> message` ; instead `message`), on version 1.19+
* unsignedContent -- unsigned formatted chat contents ; should only be present when the message is modified and server has chat previews disabled - only on version 1.19 - 1.19.2
* formattedMessage -- (JSON) the chat message preformatted, if done on server side
* plainMessage -- (Plaintext) the chat message without formatting (for example no `<username> message` ; instead `message`), on version 1.19+
* unsignedContent -- (JSON) unsigned formatted chat contents ; should only be present when the message is modified and server has chat previews disabled - only on version 1.19 - 1.19.2
* type -- the message type - on 1.19, which format string to use to render message ; below, the place where the message is displayed (for example chat or action bar)
* sender -- the UUID of the player sending the message
* senderTeam -- scoreboard team of the player (pre 1.19)
@ -279,7 +279,7 @@ Called when a chat message from another player arrives. The emitted object conta
### `systemChat` event
Called when a system chat message arrives. A system chat message is any message not sent by a player. The emitted object contains:
* formattedMessage -- the chat message preformatted
* formattedMessage -- (JSON) the chat message preformatted
* positionId -- the chat type of the message. 1 for system chat and 2 for actionbar
See the [chat example](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/examples/client_chat/client_chat.js#L1) for usage.

View file

@ -266,7 +266,7 @@ module.exports = function (client, options) {
plain: packet.plainMessage,
decorated: packet.formattedMessage
},
messageHash: packet.bodyDigest,
messageHash: packet.messageHash,
timestamp: packet.timestamp,
salt: packet.salt,
lastSeen: packet.previousMessages
@ -297,6 +297,39 @@ module.exports = function (client, options) {
})
})
const sliceIndexForMessage = {}
client.on('declare_commands', (packet) => {
const nodes = packet.nodes
for (const commandNode of nodes[0].children) {
const node = nodes[commandNode]
const commandName = node.extraNodeData.name
function visit (node, depth = 0) {
const name = node.extraNodeData.name
if (node.extraNodeData.parser === 'minecraft:message') {
sliceIndexForMessage[commandName] = [name, depth]
}
for (const child of node.children) {
visit(nodes[child], depth + 1)
}
}
visit(node, 0)
}
})
function signaturesForCommand (string, ts, salt) {
const signatures = []
const slices = string.split(' ')
if (sliceIndexForMessage[slices[0]]) {
const [fieldName, sliceIndex] = sliceIndexForMessage[slices[0]]
const sliced = slices.slice(sliceIndex)
if (sliced.length > 0) {
const signable = sliced.join(' ')
signatures.push({ argumentName: fieldName, signature: client.signMessage(signable, ts, salt) })
}
}
return signatures
}
// Chat Sending
let pendingChatRequest
let lastPreviewRequestId = 0
@ -305,6 +338,23 @@ module.exports = function (client, options) {
options.timestamp = options.timestamp || BigInt(Date.now())
options.salt = options.salt || 1n
if (message.startsWith('/') && !mcData.supportFeature('useChatSessions')) {
const command = message.slice(1)
client.write('chat_command', {
command,
timestamp: options.timestamp,
salt: options.salt,
argumentSignatures: signaturesForCommand(command, options.timestamp, options.salt),
signedPreview: options.didPreview,
previousMessages: client._lastSeenMessages.map((e) => ({
messageSender: e.sender,
messageSignature: e.signature
})),
lastRejectedMessage: client._lastRejectedMessage
})
return
}
if (mcData.supportFeature('useChatSessions')) {
let acc = 0
const acknowledgements = []
@ -351,7 +401,7 @@ module.exports = function (client, options) {
lastRejectedMessage: client._lastRejectedMessage
})
client._lastSeenMessages.pending = 0
} else {
} else if (client.serverFeatures.chatPreview) {
client.write('chat_preview', {
query: lastPreviewRequestId,
message

View file

@ -7,12 +7,9 @@ const { mojangPublicKeyPem } = require('./constants')
class VerificationError extends Error {}
function validateLastMessages (pending, lastSeen, lastRejected) {
if (lastRejected) {
const rejectedTs = pending.get(lastRejected.sender, lastRejected.signature)
if (!rejectedTs) {
throw new VerificationError(`Client rejected a message we never sent from '${lastRejected.sender}'`)
} else {
pending.acknowledge(lastRejected.sender, lastRejected.signature)
}
const rejectedTime = pending.get(lastRejected.sender, lastRejected.signature)
if (rejectedTime) pending.acknowledge(lastRejected.sender, lastRejected.signature)
else throw new VerificationError(`Client rejected a message we never sent from '${lastRejected.sender}'`)
}
let lastTimestamp