fix bot/msg (offline-only support)
This commit is contained in:
@ -30,20 +30,24 @@ func attachPlayerMsg(c *bot.Client, p *basic.Player, handler func(msg chat.Messa
|
||||
bot.PacketHandler{
|
||||
Priority: 64, ID: packetid.ClientboundPlayerChat,
|
||||
F: func(packet pk.Packet) error {
|
||||
var message sign.PlayerMessage
|
||||
var chatType chat.Type
|
||||
if err := packet.Scan(&message, &chatType); err != nil {
|
||||
var (
|
||||
sender pk.UUID
|
||||
index pk.VarInt
|
||||
signature pk.Option[sign.Signature, *sign.Signature]
|
||||
body sign.MessageBody
|
||||
unsignedContent pk.Option[chat.Message, *chat.Message]
|
||||
filter sign.FilterMask
|
||||
chatType chat.Type
|
||||
)
|
||||
if err := packet.Scan(&sender, &index, &signature, &body, &unsignedContent, &filter, &chatType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var content chat.Message
|
||||
if message.MessageBody.DecoratedMsg != nil {
|
||||
data, _ := message.MessageBody.DecoratedMsg.MarshalJSON()
|
||||
if err := content.UnmarshalJSON(data); err != nil {
|
||||
return err
|
||||
}
|
||||
if unsignedContent.Has {
|
||||
content = unsignedContent.Val
|
||||
} else {
|
||||
content = chat.Text(message.MessageBody.PlainMsg)
|
||||
content = chat.Text(body.PlainMsg)
|
||||
}
|
||||
|
||||
ct := p.WorldInfo.RegistryCodec.ChatType.FindByID(chatType.ID)
|
||||
@ -74,11 +78,9 @@ func (m *Manager) SendMessage(msg string) error {
|
||||
pk.String(msg),
|
||||
pk.Long(time.Now().UnixMilli()),
|
||||
pk.Long(salt),
|
||||
pk.ByteArray{},
|
||||
pk.Boolean(false),
|
||||
pk.Array([]sign.HistoryMessage{}),
|
||||
pk.Option[sign.HistoryMessage, *sign.HistoryMessage]{
|
||||
Has: false,
|
||||
pk.Boolean(false), // signature
|
||||
sign.HistoryUpdate{
|
||||
Acknowledged: pk.NewFixedBitSet(20),
|
||||
},
|
||||
))
|
||||
return err
|
||||
|
@ -1,122 +1,122 @@
|
||||
package sign
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/Tnze/go-mc/chat"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type MessageHeader struct {
|
||||
PrevSignature []byte
|
||||
Sender uuid.UUID
|
||||
}
|
||||
|
||||
func (m *MessageHeader) WriteTo(w io.Writer) (n int64, err error) {
|
||||
hasSignature := pk.Boolean(len(m.PrevSignature) > 0)
|
||||
n, err = hasSignature.WriteTo(w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if hasSignature {
|
||||
n2, err := pk.ByteArray(m.PrevSignature).WriteTo(w)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
n3, err := pk.UUID(m.Sender).WriteTo(w)
|
||||
return n + n3, err
|
||||
}
|
||||
|
||||
func (m *MessageHeader) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
var hasSignature pk.Boolean
|
||||
n, err = hasSignature.ReadFrom(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if hasSignature {
|
||||
n2, err := (*pk.ByteArray)(&m.PrevSignature).ReadFrom(r)
|
||||
n += n2
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
n3, err := (*pk.UUID)(&m.Sender).ReadFrom(r)
|
||||
return n + n3, err
|
||||
}
|
||||
|
||||
func (m *MessageHeader) Hash(bodyHash []byte) []byte {
|
||||
hash := sha256.New()
|
||||
if m.PrevSignature != nil {
|
||||
hash.Write(m.PrevSignature)
|
||||
}
|
||||
hash.Write(m.Sender[:])
|
||||
hash.Write(bodyHash)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
type MessageBody struct {
|
||||
PlainMsg string
|
||||
DecoratedMsg json.RawMessage
|
||||
Timestamp time.Time
|
||||
Salt int64
|
||||
History []HistoryMessage
|
||||
PlainMsg string
|
||||
Timestamp time.Time
|
||||
Salt int64
|
||||
LastSeen []PackedSignature
|
||||
}
|
||||
|
||||
func (m *MessageBody) WriteTo(w io.Writer) (n int64, err error) {
|
||||
return pk.Tuple{
|
||||
pk.String(m.PlainMsg),
|
||||
pk.Boolean(m.DecoratedMsg != nil),
|
||||
pk.Opt{
|
||||
Has: m.DecoratedMsg != nil,
|
||||
Field: pk.ByteArray(m.DecoratedMsg),
|
||||
},
|
||||
pk.Long(m.Timestamp.UnixMilli()),
|
||||
pk.Long(m.Salt),
|
||||
pk.Array(&m.History),
|
||||
pk.Array(m.LastSeen),
|
||||
}.WriteTo(w)
|
||||
}
|
||||
|
||||
func (m *MessageBody) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
var hasContent pk.Boolean
|
||||
var timestamp pk.Long
|
||||
n, err = pk.Tuple{
|
||||
(*pk.String)(&m.PlainMsg),
|
||||
&hasContent,
|
||||
pk.Opt{
|
||||
Has: &hasContent,
|
||||
Field: (*pk.ByteArray)(&m.DecoratedMsg),
|
||||
},
|
||||
×tamp,
|
||||
(*pk.Long)(&m.Salt),
|
||||
pk.Array(&m.History),
|
||||
pk.Array(&m.LastSeen),
|
||||
}.ReadFrom(r)
|
||||
m.Timestamp = time.UnixMilli(int64(timestamp))
|
||||
return
|
||||
}
|
||||
|
||||
func (m *MessageBody) Hash() []byte {
|
||||
hash := sha256.New()
|
||||
_ = binary.Write(hash, binary.BigEndian, m.Salt)
|
||||
_ = binary.Write(hash, binary.BigEndian, m.Timestamp.Unix())
|
||||
hash.Write([]byte(m.PlainMsg))
|
||||
hash.Write([]byte{70})
|
||||
if m.DecoratedMsg != nil {
|
||||
decorated, _ := m.DecoratedMsg.MarshalJSON()
|
||||
hash.Write(decorated)
|
||||
type HistoryMessage struct {
|
||||
Sender uuid.UUID
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
func (p *HistoryMessage) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
n, err = (*pk.UUID)(&p.Sender).ReadFrom(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, v := range m.History {
|
||||
hash.Write([]byte{70})
|
||||
hash.Write(v.Sender[:])
|
||||
hash.Write(v.Signature)
|
||||
n2, err := (*pk.ByteArray)(&p.Signature).ReadFrom(r)
|
||||
return n + n2, err
|
||||
}
|
||||
|
||||
func (p HistoryMessage) WriteTo(w io.Writer) (n int64, err error) {
|
||||
n, err = pk.UUID(p.Sender).WriteTo(w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2, err := pk.ByteArray(p.Signature).WriteTo(w)
|
||||
return n + n2, err
|
||||
}
|
||||
|
||||
type HistoryUpdate struct {
|
||||
Offset pk.VarInt
|
||||
Acknowledged pk.FixedBitSet // n == 20
|
||||
}
|
||||
|
||||
func (h HistoryUpdate) WriteTo(w io.Writer) (n int64, err error) {
|
||||
return pk.Tuple{h.Offset, h.Acknowledged}.WriteTo(w)
|
||||
}
|
||||
|
||||
func (h *HistoryUpdate) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
return pk.Tuple{&h.Offset, &h.Acknowledged}.ReadFrom(r)
|
||||
}
|
||||
|
||||
type Signature [256]byte
|
||||
|
||||
func (s Signature) WriteTo(w io.Writer) (n int64, err error) {
|
||||
n2, err := w.Write(s[:])
|
||||
return int64(n2), err
|
||||
}
|
||||
|
||||
func (s *Signature) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
n2, err := r.Read(s[:])
|
||||
return int64(n2), err
|
||||
}
|
||||
|
||||
type PackedSignature struct {
|
||||
ID int32
|
||||
*Signature
|
||||
}
|
||||
|
||||
func (p PackedSignature) WriteTo(w io.Writer) (n int64, err error) {
|
||||
n1, err := pk.VarInt(p.ID + 1).WriteTo(w)
|
||||
if err != nil {
|
||||
return n1, err
|
||||
}
|
||||
if p.Signature != nil {
|
||||
n2, err := w.Write(p.Signature[:])
|
||||
return n1 + int64(n2), err
|
||||
}
|
||||
return n1, err
|
||||
}
|
||||
|
||||
func (p PackedSignature) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
n1, err := (*pk.VarInt)(&p.ID).ReadFrom(r)
|
||||
if err != nil {
|
||||
return n1, err
|
||||
}
|
||||
|
||||
if p.ID == -1 {
|
||||
if p.Signature == nil {
|
||||
p.Signature = new(Signature)
|
||||
}
|
||||
n2, err := r.Read(p.Signature[:])
|
||||
return n1 + int64(n2), err
|
||||
} else {
|
||||
p.Signature = nil
|
||||
return n1, err
|
||||
}
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
type FilterMask struct {
|
||||
@ -150,70 +150,3 @@ func (f *FilterMask) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type PlayerMessage struct {
|
||||
MessageHeader
|
||||
MessageSignature []byte
|
||||
MessageBody
|
||||
UnsignedContent *chat.Message
|
||||
FilterMask
|
||||
}
|
||||
|
||||
func (msg *PlayerMessage) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
var hasUnsignedContent pk.Boolean
|
||||
return pk.Tuple{
|
||||
&msg.MessageHeader,
|
||||
(*pk.ByteArray)(&msg.MessageSignature),
|
||||
&msg.MessageBody,
|
||||
&hasUnsignedContent,
|
||||
pk.Opt{
|
||||
Has: &hasUnsignedContent,
|
||||
Field: func() pk.FieldDecoder {
|
||||
msg.UnsignedContent = new(chat.Message)
|
||||
return msg.UnsignedContent
|
||||
},
|
||||
},
|
||||
&msg.FilterMask,
|
||||
}.ReadFrom(r)
|
||||
}
|
||||
|
||||
func (msg *PlayerMessage) WriteTo(w io.Writer) (n int64, err error) {
|
||||
return pk.Tuple{
|
||||
&msg.MessageHeader,
|
||||
pk.ByteArray(msg.MessageSignature),
|
||||
&msg.MessageBody,
|
||||
pk.Boolean(msg.UnsignedContent != nil),
|
||||
pk.Opt{
|
||||
Has: msg.UnsignedContent != nil,
|
||||
Field: msg.UnsignedContent,
|
||||
},
|
||||
&msg.FilterMask,
|
||||
}.WriteTo(w)
|
||||
}
|
||||
|
||||
func (msg *PlayerMessage) Hash() []byte {
|
||||
return msg.MessageHeader.Hash(msg.MessageBody.Hash())
|
||||
}
|
||||
|
||||
type HistoryMessage struct {
|
||||
Sender uuid.UUID
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
func (p *HistoryMessage) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
n, err = (*pk.UUID)(&p.Sender).ReadFrom(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2, err := (*pk.ByteArray)(&p.Signature).ReadFrom(r)
|
||||
return n + n2, err
|
||||
}
|
||||
|
||||
func (p HistoryMessage) WriteTo(w io.Writer) (n int64, err error) {
|
||||
n, err = pk.UUID(p.Sender).WriteTo(w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n2, err := pk.ByteArray(p.Signature).WriteTo(w)
|
||||
return n + n2, err
|
||||
}
|
||||
|
@ -1,55 +1 @@
|
||||
package sign
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"encoding/base64"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func TestMessageBody_Hash(t *testing.T) {
|
||||
msg := PlayerMessage{
|
||||
MessageHeader: MessageHeader{
|
||||
PrevSignature: nil,
|
||||
Sender: uuid.MustParse("58f6356e-b30c-4811-8bfc-d72a9ee99e73"),
|
||||
},
|
||||
MessageSignature: fromBase64("L+gR1hrubxVdhPAe6J+nQCH4U+jsUvJDJE+dzsL8DJwpHfUwT4dgSwm7mI/u8rVxrjPVial1DU0sPZodaGVqcSqApyK38bJThWpmojYtieT63hcsgAZzhGNG0GUrykEzHIMPvAnO0bEBmOqPKWjp/kDxhUgF1kKgmQmiOb1fTazi9dVxGuepVkFXknhp7aZBvQ4oQ94bRY5lTMoWyvNcs3CUpVdeFuWwIVnRAIn+hQQ5rDBvWTgKpFTOuxcCOf6hbtPOO2HZ7TT0rsM1D1LV0R9oHUqlEe4nB0E/vT3GdcplSQTSWc7dDmwTjB+wFeGxrNjFP3FEt3he6a+8Q1svlw=="),
|
||||
MessageBody: MessageBody{
|
||||
PlainMsg: "123",
|
||||
DecoratedMsg: nil,
|
||||
Timestamp: time.Unix(1669990398, 750000000),
|
||||
Salt: -5503869105027681791,
|
||||
History: nil,
|
||||
},
|
||||
UnsignedContent: nil,
|
||||
FilterMask: FilterMask{},
|
||||
}
|
||||
hash := msg.MessageBody.Hash()
|
||||
want := []byte{
|
||||
0x40, 0x2f, 0x63, 0xf1, 0x41, 0x64, 0x83, 0xea,
|
||||
0x64, 0xbc, 0xe1, 0xab, 0x4f, 0xa1, 0xdd, 0xcf,
|
||||
0x31, 0x6b, 0xdf, 0x9, 0xd3, 0xe3, 0x0, 0xed,
|
||||
0xd9, 0x9d, 0x61, 0xb2, 0xfe, 0xe1, 0x23, 0x38,
|
||||
}
|
||||
if !bytes.Equal(hash, want) {
|
||||
t.Errorf("hash not match: want %v, got: %v", want, hash)
|
||||
}
|
||||
N := new(big.Int)
|
||||
N.SetString("19764335557512872060688171398766153113124870942516110890430525316014258628424563821100465499350547856280308462415364939681918846480558609475927282823778386281239015421014618416397562105532153533222767841904849714784545929150813290491806771374240538006775842793512508846836865954304676946257326405255232806869270545112507181469911882584371001804731679283550070980294409246775152428394531383836676761395396452034288295355452943368136472112108083541314359681019016586668426966809565492641015821429276348346645505643438759550398087660394335140584223095644803819139358171070866744685891950091018380254474327892983538632197", 10)
|
||||
if err := rsa.VerifyPKCS1v15(&rsa.PublicKey{N: N, E: 65537}, crypto.SHA256, msg.Hash(), msg.MessageSignature); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func fromBase64(s string) []byte {
|
||||
b, err := base64.StdEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
@ -107,9 +107,9 @@ func onDeath() error {
|
||||
|
||||
func onGameStart() error {
|
||||
log.Println("Game start")
|
||||
//if err := chatHandler.SendMessage("Hello, world"); err != nil {
|
||||
// return err
|
||||
//}
|
||||
if err := chatHandler.SendMessage("Hello, world"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil // if err isn't nil, HandleGame() will return it.
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,9 @@ type (
|
||||
|
||||
// BitSet represents Java's BitSet, a list of bits.
|
||||
BitSet []int64
|
||||
|
||||
// FixedBitSet is a fixed size BitSet
|
||||
FixedBitSet []byte
|
||||
)
|
||||
|
||||
const (
|
||||
@ -536,3 +539,34 @@ func (b BitSet) Set(index int, value bool) {
|
||||
b[index/64] &= ^(1 << (index % 64))
|
||||
}
|
||||
}
|
||||
|
||||
// NewFixedBitSet make a [FixedBitSet] which can store n bits at least.
|
||||
// If n <= 0, return nil
|
||||
func NewFixedBitSet(n int64) FixedBitSet {
|
||||
if n <= 0 {
|
||||
return nil
|
||||
}
|
||||
return make(FixedBitSet, (n-1)/8+1)
|
||||
}
|
||||
|
||||
func (f FixedBitSet) WriteTo(w io.Writer) (n int64, err error) {
|
||||
n2, err := w.Write(f)
|
||||
return int64(n2), err
|
||||
}
|
||||
|
||||
func (f FixedBitSet) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
n2, err := r.Read(f)
|
||||
return int64(n2), err
|
||||
}
|
||||
|
||||
func (f FixedBitSet) Get(index int) bool {
|
||||
return (f[index/8] & (1 << (index % 8))) != 0
|
||||
}
|
||||
|
||||
func (f FixedBitSet) Set(index int, value bool) {
|
||||
if value {
|
||||
f[index/8] |= 1 << (index % 8)
|
||||
} else {
|
||||
f[index/8] &= ^(1 << (index % 8))
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package server
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/Tnze/go-mc/internal/queue"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
"github.com/Tnze/go-mc/net/queue"
|
||||
)
|
||||
|
||||
// Packet758 is a packet in protocol 757.
|
||||
|
Reference in New Issue
Block a user