mirror of
https://github.com/cwinfo/matterbridge.git
synced 2025-07-01 18:16:17 +00:00
Add dependencies/vendor (whatsapp)
This commit is contained in:
177
vendor/go.mau.fi/whatsmeow/binary/attrs.go
vendored
Normal file
177
vendor/go.mau.fi/whatsmeow/binary/attrs.go
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
// Copyright (c) 2021 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package binary
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
)
|
||||
|
||||
// AttrUtility is a helper struct for reading multiple XML attributes and checking for errors afterwards.
|
||||
//
|
||||
// The functions return values directly and append any decoding errors to the Errors slice. The
|
||||
// slice can then be checked after all necessary attributes are read, instead of having to check
|
||||
// each attribute for errors separately.
|
||||
type AttrUtility struct {
|
||||
Attrs Attrs
|
||||
Errors []error
|
||||
}
|
||||
|
||||
// AttrGetter returns the AttrUtility for this Node.
|
||||
func (n *Node) AttrGetter() *AttrUtility {
|
||||
return &AttrUtility{Attrs: n.Attrs, Errors: make([]error, 0)}
|
||||
}
|
||||
|
||||
func (au *AttrUtility) GetJID(key string, require bool) (jidVal types.JID, ok bool) {
|
||||
var val interface{}
|
||||
if val, ok = au.Attrs[key]; !ok {
|
||||
if require {
|
||||
au.Errors = append(au.Errors, fmt.Errorf("didn't find required JID attribute '%s'", key))
|
||||
}
|
||||
} else if jidVal, ok = val.(types.JID); !ok {
|
||||
au.Errors = append(au.Errors, fmt.Errorf("expected attribute '%s' to be JID, but was %T", key, val))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OptionalJID returns the JID under the given key. If there's no valid JID under the given key, this will return nil.
|
||||
// However, if the attribute is completely missing, this will not store an error.
|
||||
func (au *AttrUtility) OptionalJID(key string) *types.JID {
|
||||
jid, ok := au.GetJID(key, false)
|
||||
if ok {
|
||||
return &jid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OptionalJIDOrEmpty returns the JID under the given key. If there's no valid JID under the given key, this will return an empty JID.
|
||||
// However, if the attribute is completely missing, this will not store an error.
|
||||
func (au *AttrUtility) OptionalJIDOrEmpty(key string) types.JID {
|
||||
jid, ok := au.GetJID(key, false)
|
||||
if ok {
|
||||
return jid
|
||||
}
|
||||
return types.EmptyJID
|
||||
}
|
||||
|
||||
// JID returns the JID under the given key.
|
||||
// If there's no valid JID under the given key, an error will be stored and a blank JID struct will be returned.
|
||||
func (au *AttrUtility) JID(key string) types.JID {
|
||||
jid, _ := au.GetJID(key, true)
|
||||
return jid
|
||||
}
|
||||
|
||||
func (au *AttrUtility) GetString(key string, require bool) (strVal string, ok bool) {
|
||||
var val interface{}
|
||||
if val, ok = au.Attrs[key]; !ok {
|
||||
if require {
|
||||
au.Errors = append(au.Errors, fmt.Errorf("didn't find required attribute '%s'", key))
|
||||
}
|
||||
} else if strVal, ok = val.(string); !ok {
|
||||
au.Errors = append(au.Errors, fmt.Errorf("expected attribute '%s' to be string, but was %T", key, val))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (au *AttrUtility) GetInt64(key string, require bool) (int64, bool) {
|
||||
if strVal, ok := au.GetString(key, require); !ok {
|
||||
return 0, false
|
||||
} else if intVal, err := strconv.ParseInt(strVal, 10, 64); err != nil {
|
||||
au.Errors = append(au.Errors, fmt.Errorf("failed to parse int in attribute '%s': %w", key, err))
|
||||
return 0, false
|
||||
} else {
|
||||
return intVal, true
|
||||
}
|
||||
}
|
||||
|
||||
func (au *AttrUtility) GetUint64(key string, require bool) (uint64, bool) {
|
||||
if strVal, ok := au.GetString(key, require); !ok {
|
||||
return 0, false
|
||||
} else if intVal, err := strconv.ParseUint(strVal, 10, 64); err != nil {
|
||||
au.Errors = append(au.Errors, fmt.Errorf("failed to parse uint in attribute '%s': %w", key, err))
|
||||
return 0, false
|
||||
} else {
|
||||
return intVal, true
|
||||
}
|
||||
}
|
||||
|
||||
func (au *AttrUtility) GetBool(key string, require bool) (bool, bool) {
|
||||
if strVal, ok := au.GetString(key, require); !ok {
|
||||
return false, false
|
||||
} else if boolVal, err := strconv.ParseBool(strVal); err != nil {
|
||||
au.Errors = append(au.Errors, fmt.Errorf("failed to parse bool in attribute '%s': %w", key, err))
|
||||
return false, false
|
||||
} else {
|
||||
return boolVal, true
|
||||
}
|
||||
}
|
||||
|
||||
// OptionalString returns the string under the given key.
|
||||
func (au *AttrUtility) OptionalString(key string) string {
|
||||
strVal, _ := au.GetString(key, false)
|
||||
return strVal
|
||||
}
|
||||
|
||||
// String returns the string under the given key.
|
||||
// If there's no valid string under the given key, an error will be stored and an empty string will be returned.
|
||||
func (au *AttrUtility) String(key string) string {
|
||||
strVal, _ := au.GetString(key, true)
|
||||
return strVal
|
||||
}
|
||||
|
||||
func (au *AttrUtility) OptionalInt(key string) int {
|
||||
val, _ := au.GetInt64(key, false)
|
||||
return int(val)
|
||||
}
|
||||
|
||||
func (au *AttrUtility) Int(key string) int {
|
||||
val, _ := au.GetInt64(key, true)
|
||||
return int(val)
|
||||
}
|
||||
|
||||
func (au *AttrUtility) Int64(key string) int64 {
|
||||
val, _ := au.GetInt64(key, true)
|
||||
return val
|
||||
}
|
||||
|
||||
func (au *AttrUtility) Uint64(key string) uint64 {
|
||||
val, _ := au.GetUint64(key, true)
|
||||
return val
|
||||
}
|
||||
|
||||
func (au *AttrUtility) OptionalBool(key string) bool {
|
||||
val, _ := au.GetBool(key, false)
|
||||
return val
|
||||
}
|
||||
|
||||
func (au *AttrUtility) Bool(key string) bool {
|
||||
val, _ := au.GetBool(key, true)
|
||||
return val
|
||||
}
|
||||
|
||||
// OK returns true if there are no errors.
|
||||
func (au *AttrUtility) OK() bool {
|
||||
return len(au.Errors) == 0
|
||||
}
|
||||
|
||||
// Error returns the list of errors as a single error interface, or nil if there are no errors.
|
||||
func (au *AttrUtility) Error() error {
|
||||
if au.OK() {
|
||||
return nil
|
||||
}
|
||||
return ErrorList(au.Errors)
|
||||
}
|
||||
|
||||
// ErrorList is a list of errors that implements the error interface itself.
|
||||
type ErrorList []error
|
||||
|
||||
// Error returns all the errors in the list as a string.
|
||||
func (el ErrorList) Error() string {
|
||||
return fmt.Sprintf("%+v", []error(el))
|
||||
}
|
353
vendor/go.mau.fi/whatsmeow/binary/decoder.go
vendored
Normal file
353
vendor/go.mau.fi/whatsmeow/binary/decoder.go
vendored
Normal file
@ -0,0 +1,353 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"go.mau.fi/whatsmeow/binary/token"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
)
|
||||
|
||||
type binaryDecoder struct {
|
||||
data []byte
|
||||
index int
|
||||
}
|
||||
|
||||
func newDecoder(data []byte) *binaryDecoder {
|
||||
return &binaryDecoder{data, 0}
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) checkEOS(length int) error {
|
||||
if r.index+length > len(r.data) {
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readByte() (byte, error) {
|
||||
if err := r.checkEOS(1); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
b := r.data[r.index]
|
||||
r.index++
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readIntN(n int, littleEndian bool) (int, error) {
|
||||
if err := r.checkEOS(n); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var ret int
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
var curShift int
|
||||
if littleEndian {
|
||||
curShift = i
|
||||
} else {
|
||||
curShift = n - i - 1
|
||||
}
|
||||
ret |= int(r.data[r.index+i]) << uint(curShift*8)
|
||||
}
|
||||
|
||||
r.index += n
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readInt8(littleEndian bool) (int, error) {
|
||||
return r.readIntN(1, littleEndian)
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readInt16(littleEndian bool) (int, error) {
|
||||
return r.readIntN(2, littleEndian)
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readInt20() (int, error) {
|
||||
if err := r.checkEOS(3); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
ret := ((int(r.data[r.index]) & 15) << 16) + (int(r.data[r.index+1]) << 8) + int(r.data[r.index+2])
|
||||
r.index += 3
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readInt32(littleEndian bool) (int, error) {
|
||||
return r.readIntN(4, littleEndian)
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readPacked8(tag int) (string, error) {
|
||||
startByte, err := r.readByte()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var build strings.Builder
|
||||
|
||||
for i := 0; i < int(startByte&127); i++ {
|
||||
currByte, err := r.readByte()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
lower, err := unpackByte(tag, currByte&0xF0>>4)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
upper, err := unpackByte(tag, currByte&0x0F)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
build.WriteByte(lower)
|
||||
build.WriteByte(upper)
|
||||
}
|
||||
|
||||
ret := build.String()
|
||||
if startByte>>7 != 0 {
|
||||
ret = ret[:len(ret)-1]
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func unpackByte(tag int, value byte) (byte, error) {
|
||||
switch tag {
|
||||
case token.Nibble8:
|
||||
return unpackNibble(value)
|
||||
case token.Hex8:
|
||||
return unpackHex(value)
|
||||
default:
|
||||
return 0, fmt.Errorf("unpackByte with unknown tag %d", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func unpackNibble(value byte) (byte, error) {
|
||||
switch {
|
||||
case value < 10:
|
||||
return '0' + value, nil
|
||||
case value == 10:
|
||||
return '-', nil
|
||||
case value == 11:
|
||||
return '.', nil
|
||||
case value == 15:
|
||||
return 0, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unpackNibble with value %d", value)
|
||||
}
|
||||
}
|
||||
|
||||
func unpackHex(value byte) (byte, error) {
|
||||
switch {
|
||||
case value < 10:
|
||||
return '0' + value, nil
|
||||
case value < 16:
|
||||
return 'A' + value - 10, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unpackHex with value %d", value)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readListSize(tag int) (int, error) {
|
||||
switch tag {
|
||||
case token.ListEmpty:
|
||||
return 0, nil
|
||||
case token.List8:
|
||||
return r.readInt8(false)
|
||||
case token.List16:
|
||||
return r.readInt16(false)
|
||||
default:
|
||||
return 0, fmt.Errorf("readListSize with unknown tag %d at position %d", tag, r.index)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) read(string bool) (interface{}, error) {
|
||||
tagByte, err := r.readByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tag := int(tagByte)
|
||||
switch tag {
|
||||
case token.ListEmpty:
|
||||
return nil, nil
|
||||
case token.List8, token.List16:
|
||||
return r.readList(tag)
|
||||
case token.Binary8:
|
||||
size, err := r.readInt8(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.readBytesOrString(size, string)
|
||||
case token.Binary20:
|
||||
size, err := r.readInt20()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.readBytesOrString(size, string)
|
||||
case token.Binary32:
|
||||
size, err := r.readInt32(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.readBytesOrString(size, string)
|
||||
case token.Dictionary0, token.Dictionary1, token.Dictionary2, token.Dictionary3:
|
||||
i, err := r.readInt8(false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return token.GetDoubleToken(tag-token.Dictionary0, i)
|
||||
case token.JIDPair:
|
||||
return r.readJIDPair()
|
||||
case token.ADJID:
|
||||
return r.readADJID()
|
||||
case token.Nibble8, token.Hex8:
|
||||
return r.readPacked8(tag)
|
||||
default:
|
||||
if tag >= 1 && tag < len(token.SingleByteTokens) {
|
||||
return token.SingleByteTokens[tag], nil
|
||||
}
|
||||
return "", fmt.Errorf("%w %d at position %d", ErrInvalidToken, tag, r.index)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readJIDPair() (interface{}, error) {
|
||||
user, err := r.read(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
server, err := r.read(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if server == nil {
|
||||
return nil, ErrInvalidJIDType
|
||||
} else if user == nil {
|
||||
return types.NewJID("", server.(string)), nil
|
||||
}
|
||||
return types.NewJID(user.(string), server.(string)), nil
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readADJID() (interface{}, error) {
|
||||
agent, err := r.readByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
device, err := r.readByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, err := r.read(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.NewADJID(user.(string), agent, device), nil
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readAttributes(n int) (Attrs, error) {
|
||||
if n == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ret := make(Attrs)
|
||||
for i := 0; i < n; i++ {
|
||||
keyIfc, err := r.read(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, ok := keyIfc.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%[1]w at position %[3]d (%[2]T): %+[2]v", ErrNonStringKey, key, r.index)
|
||||
}
|
||||
|
||||
ret[key], err = r.read(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readList(tag int) ([]Node, error) {
|
||||
size, err := r.readListSize(tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make([]Node, size)
|
||||
for i := 0; i < size; i++ {
|
||||
n, err := r.readNode()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret[i] = *n
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readNode() (*Node, error) {
|
||||
ret := &Node{}
|
||||
|
||||
size, err := r.readInt8(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
listSize, err := r.readListSize(size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawDesc, err := r.read(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Tag = rawDesc.(string)
|
||||
if listSize == 0 || ret.Tag == "" {
|
||||
return nil, ErrInvalidNode
|
||||
}
|
||||
|
||||
ret.Attrs, err = r.readAttributes((listSize - 1) >> 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if listSize%2 == 1 {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
ret.Content, err = r.read(false)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readBytesOrString(length int, asString bool) (interface{}, error) {
|
||||
data, err := r.readRaw(length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if asString {
|
||||
return string(data), nil
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (r *binaryDecoder) readRaw(length int) ([]byte, error) {
|
||||
if err := r.checkEOS(length); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := r.data[r.index : r.index+length]
|
||||
r.index += length
|
||||
|
||||
return ret, nil
|
||||
}
|
293
vendor/go.mau.fi/whatsmeow/binary/encoder.go
vendored
Normal file
293
vendor/go.mau.fi/whatsmeow/binary/encoder.go
vendored
Normal file
@ -0,0 +1,293 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"go.mau.fi/whatsmeow/binary/token"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
)
|
||||
|
||||
type binaryEncoder struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
func newEncoder() *binaryEncoder {
|
||||
return &binaryEncoder{[]byte{0}}
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) getData() []byte {
|
||||
return w.data
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) pushByte(b byte) {
|
||||
w.data = append(w.data, b)
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) pushBytes(bytes []byte) {
|
||||
w.data = append(w.data, bytes...)
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) pushIntN(value, n int, littleEndian bool) {
|
||||
for i := 0; i < n; i++ {
|
||||
var curShift int
|
||||
if littleEndian {
|
||||
curShift = i
|
||||
} else {
|
||||
curShift = n - i - 1
|
||||
}
|
||||
w.pushByte(byte((value >> uint(curShift*8)) & 0xFF))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) pushInt20(value int) {
|
||||
w.pushBytes([]byte{byte((value >> 16) & 0x0F), byte((value >> 8) & 0xFF), byte(value & 0xFF)})
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) pushInt8(value int) {
|
||||
w.pushIntN(value, 1, false)
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) pushInt16(value int) {
|
||||
w.pushIntN(value, 2, false)
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) pushInt32(value int) {
|
||||
w.pushIntN(value, 4, false)
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) pushString(value string) {
|
||||
w.pushBytes([]byte(value))
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) writeByteLength(length int) {
|
||||
if length < 256 {
|
||||
w.pushByte(token.Binary8)
|
||||
w.pushInt8(length)
|
||||
} else if length < (1 << 20) {
|
||||
w.pushByte(token.Binary20)
|
||||
w.pushInt20(length)
|
||||
} else if length < math.MaxInt32 {
|
||||
w.pushByte(token.Binary32)
|
||||
w.pushInt32(length)
|
||||
} else {
|
||||
panic(fmt.Errorf("length is too large: %d", length))
|
||||
}
|
||||
}
|
||||
|
||||
const tagSize = 1
|
||||
|
||||
func (w *binaryEncoder) writeNode(n Node) {
|
||||
if n.Tag == "0" {
|
||||
w.pushByte(token.List8)
|
||||
w.pushByte(token.ListEmpty)
|
||||
return
|
||||
}
|
||||
|
||||
hasContent := 0
|
||||
if n.Content != nil {
|
||||
hasContent = 1
|
||||
}
|
||||
|
||||
w.writeListStart(2*len(n.Attrs) + tagSize + hasContent)
|
||||
w.writeString(n.Tag)
|
||||
w.writeAttributes(n.Attrs)
|
||||
if n.Content != nil {
|
||||
w.write(n.Content)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) write(data interface{}) {
|
||||
switch typedData := data.(type) {
|
||||
case nil:
|
||||
w.pushByte(token.ListEmpty)
|
||||
case types.JID:
|
||||
w.writeJID(typedData)
|
||||
case string:
|
||||
w.writeString(typedData)
|
||||
case int:
|
||||
w.writeString(strconv.Itoa(typedData))
|
||||
case int32:
|
||||
w.writeString(strconv.FormatInt(int64(typedData), 10))
|
||||
case uint:
|
||||
w.writeString(strconv.FormatUint(uint64(typedData), 10))
|
||||
case uint32:
|
||||
w.writeString(strconv.FormatUint(uint64(typedData), 10))
|
||||
case int64:
|
||||
w.writeString(strconv.FormatInt(typedData, 10))
|
||||
case uint64:
|
||||
w.writeString(strconv.FormatUint(typedData, 10))
|
||||
case bool:
|
||||
w.writeString(strconv.FormatBool(typedData))
|
||||
case []byte:
|
||||
w.writeBytes(typedData)
|
||||
case []Node:
|
||||
w.writeListStart(len(typedData))
|
||||
for _, n := range typedData {
|
||||
w.writeNode(n)
|
||||
}
|
||||
default:
|
||||
panic(fmt.Errorf("%w: %T", ErrInvalidType, typedData))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) writeString(data string) {
|
||||
var dictIndex byte
|
||||
if tokenIndex, ok := token.IndexOfSingleToken(data); ok {
|
||||
w.pushByte(tokenIndex)
|
||||
} else if dictIndex, tokenIndex, ok = token.IndexOfDoubleByteToken(data); ok {
|
||||
w.pushByte(token.Dictionary0 + dictIndex)
|
||||
w.pushByte(tokenIndex)
|
||||
} else if validateNibble(data) {
|
||||
w.writePackedBytes(data, token.Nibble8)
|
||||
} else if validateHex(data) {
|
||||
w.writePackedBytes(data, token.Hex8)
|
||||
} else {
|
||||
w.writeStringRaw(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) writeBytes(value []byte) {
|
||||
w.writeByteLength(len(value))
|
||||
w.pushBytes(value)
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) writeStringRaw(value string) {
|
||||
w.writeByteLength(len(value))
|
||||
w.pushString(value)
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) writeJID(jid types.JID) {
|
||||
if jid.AD {
|
||||
w.pushByte(token.ADJID)
|
||||
w.pushByte(jid.Agent)
|
||||
w.pushByte(jid.Device)
|
||||
w.writeString(jid.User)
|
||||
} else {
|
||||
w.pushByte(token.JIDPair)
|
||||
if len(jid.User) == 0 {
|
||||
w.pushByte(token.ListEmpty)
|
||||
} else {
|
||||
w.write(jid.User)
|
||||
}
|
||||
w.write(jid.Server)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) writeAttributes(attributes Attrs) {
|
||||
if attributes == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for key, val := range attributes {
|
||||
if val == "" || val == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
w.writeString(key)
|
||||
w.write(val)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) writeListStart(listSize int) {
|
||||
if listSize == 0 {
|
||||
w.pushByte(byte(token.ListEmpty))
|
||||
} else if listSize < 256 {
|
||||
w.pushByte(byte(token.List8))
|
||||
w.pushInt8(listSize)
|
||||
} else {
|
||||
w.pushByte(byte(token.List16))
|
||||
w.pushInt16(listSize)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) writePackedBytes(value string, dataType int) {
|
||||
if len(value) > token.PackedMax {
|
||||
panic(fmt.Errorf("too many bytes to pack: %d", len(value)))
|
||||
}
|
||||
|
||||
w.pushByte(byte(dataType))
|
||||
|
||||
roundedLength := byte(math.Ceil(float64(len(value)) / 2.0))
|
||||
if len(value)%2 != 0 {
|
||||
roundedLength |= 128
|
||||
}
|
||||
w.pushByte(roundedLength)
|
||||
var packer func(byte) byte
|
||||
if dataType == token.Nibble8 {
|
||||
packer = packNibble
|
||||
} else if dataType == token.Hex8 {
|
||||
packer = packHex
|
||||
} else {
|
||||
// This should only be called with the correct values
|
||||
panic(fmt.Errorf("invalid packed byte data type %v", dataType))
|
||||
}
|
||||
for i, l := 0, len(value)/2; i < l; i++ {
|
||||
w.pushByte(w.packBytePair(packer, value[2*i], value[2*i+1]))
|
||||
}
|
||||
if len(value)%2 != 0 {
|
||||
w.pushByte(w.packBytePair(packer, value[len(value)-1], '\x00'))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *binaryEncoder) packBytePair(packer func(byte) byte, part1, part2 byte) byte {
|
||||
return (packer(part1) << 4) | packer(part2)
|
||||
}
|
||||
|
||||
func validateNibble(value string) bool {
|
||||
if len(value) > token.PackedMax {
|
||||
return false
|
||||
}
|
||||
for _, char := range value {
|
||||
if !(char >= '0' && char <= '9') && char != '-' && char != '.' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func packNibble(value byte) byte {
|
||||
switch value {
|
||||
case '-':
|
||||
return 10
|
||||
case '.':
|
||||
return 11
|
||||
case 0:
|
||||
return 15
|
||||
default:
|
||||
if value >= '0' && value <= '9' {
|
||||
return value - '0'
|
||||
}
|
||||
// This should be validated beforehand
|
||||
panic(fmt.Errorf("invalid string to pack as nibble: %d / '%s'", value, string(value)))
|
||||
}
|
||||
}
|
||||
|
||||
func validateHex(value string) bool {
|
||||
if len(value) > token.PackedMax {
|
||||
return false
|
||||
}
|
||||
for _, char := range value {
|
||||
if !(char >= '0' && char <= '9') && !(char >= 'A' && char <= 'F') && !(char >= 'a' && char <= 'f') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func packHex(value byte) byte {
|
||||
switch {
|
||||
case value >= '0' && value <= '9':
|
||||
return value - '0'
|
||||
case value >= 'A' && value <= 'F':
|
||||
return 10 + value - 'A'
|
||||
case value >= 'a' && value <= 'f':
|
||||
return 10 + value - 'a'
|
||||
case value == 0:
|
||||
return 15
|
||||
default:
|
||||
// This should be validated beforehand
|
||||
panic(fmt.Errorf("invalid string to pack as hex: %d / '%s'", value, string(value)))
|
||||
}
|
||||
}
|
12
vendor/go.mau.fi/whatsmeow/binary/errors.go
vendored
Normal file
12
vendor/go.mau.fi/whatsmeow/binary/errors.go
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
package binary
|
||||
|
||||
import "errors"
|
||||
|
||||
// Errors returned by the binary XML decoder.
|
||||
var (
|
||||
ErrInvalidType = errors.New("unsupported payload type")
|
||||
ErrInvalidJIDType = errors.New("invalid JID type")
|
||||
ErrInvalidNode = errors.New("invalid node")
|
||||
ErrInvalidToken = errors.New("invalid token with tag")
|
||||
ErrNonStringKey = errors.New("non-string key")
|
||||
)
|
83
vendor/go.mau.fi/whatsmeow/binary/node.go
vendored
Normal file
83
vendor/go.mau.fi/whatsmeow/binary/node.go
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2021 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// Package binary implements encoding and decoding documents in WhatsApp's binary XML format.
|
||||
package binary
|
||||
|
||||
// Attrs is a type alias for the attributes of an XML element (Node).
|
||||
type Attrs = map[string]interface{}
|
||||
|
||||
// Node represents an XML element.
|
||||
type Node struct {
|
||||
Tag string // The tag of the element.
|
||||
Attrs Attrs // The attributes of the element.
|
||||
Content interface{} // The content inside the element. Can be nil, a list of Nodes, or a byte array.
|
||||
}
|
||||
|
||||
// GetChildren returns the Content of the node as a list of nodes. If the content is not a list of nodes, this returns nil.
|
||||
func (n *Node) GetChildren() []Node {
|
||||
if n.Content == nil {
|
||||
return nil
|
||||
}
|
||||
children, ok := n.Content.([]Node)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return children
|
||||
}
|
||||
|
||||
// GetChildrenByTag returns the same list as GetChildren, but filters it by tag first.
|
||||
func (n *Node) GetChildrenByTag(tag string) (children []Node) {
|
||||
for _, node := range n.GetChildren() {
|
||||
if node.Tag == tag {
|
||||
children = append(children, node)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOptionalChildByTag finds the first child with the given tag and returns it.
|
||||
// Each provided tag will recurse in, so this is useful for getting a specific nested element.
|
||||
func (n *Node) GetOptionalChildByTag(tags ...string) (val Node, ok bool) {
|
||||
val = *n
|
||||
Outer:
|
||||
for _, tag := range tags {
|
||||
for _, child := range val.GetChildren() {
|
||||
if child.Tag == tag {
|
||||
val = child
|
||||
continue Outer
|
||||
}
|
||||
}
|
||||
// If no matching children are found, return false
|
||||
return
|
||||
}
|
||||
// All iterations of loop found a matching child, return it
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// GetChildByTag does the same thing as GetOptionalChildByTag, but returns the Node directly without the ok boolean.
|
||||
func (n *Node) GetChildByTag(tags ...string) Node {
|
||||
node, _ := n.GetOptionalChildByTag(tags...)
|
||||
return node
|
||||
}
|
||||
|
||||
// Marshal encodes an XML element (Node) into WhatsApp's binary XML representation.
|
||||
func Marshal(n Node) ([]byte, error) {
|
||||
w := newEncoder()
|
||||
w.writeNode(n)
|
||||
return w.getData(), nil
|
||||
}
|
||||
|
||||
// Unmarshal decodes WhatsApp's binary XML representation into a Node.
|
||||
func Unmarshal(data []byte) (*Node, error) {
|
||||
r := newDecoder(data)
|
||||
n, err := r.readNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
21520
vendor/go.mau.fi/whatsmeow/binary/proto/def.pb.go
vendored
Normal file
21520
vendor/go.mau.fi/whatsmeow/binary/proto/def.pb.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vendor/go.mau.fi/whatsmeow/binary/proto/def.pb.raw
vendored
Normal file
BIN
vendor/go.mau.fi/whatsmeow/binary/proto/def.pb.raw
vendored
Normal file
Binary file not shown.
2011
vendor/go.mau.fi/whatsmeow/binary/proto/def.proto
vendored
Normal file
2011
vendor/go.mau.fi/whatsmeow/binary/proto/def.proto
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
vendor/go.mau.fi/whatsmeow/binary/proto/doc.go
vendored
Normal file
2
vendor/go.mau.fi/whatsmeow/binary/proto/doc.go
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package proto contains the compiled protobuf structs from WhatsApp's protobuf schema.
|
||||
package proto
|
88
vendor/go.mau.fi/whatsmeow/binary/token/token.go
vendored
Normal file
88
vendor/go.mau.fi/whatsmeow/binary/token/token.go
vendored
Normal file
File diff suppressed because one or more lines are too long
31
vendor/go.mau.fi/whatsmeow/binary/unpack.go
vendored
Normal file
31
vendor/go.mau.fi/whatsmeow/binary/unpack.go
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2021 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package binary
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Unpack unpacks the given decrypted data from the WhatsApp web API.
|
||||
//
|
||||
// It checks the first byte to decide whether to uncompress the data with zlib or just return as-is
|
||||
// (without the first byte). There's currently no corresponding Pack function because Marshal
|
||||
// already returns the data with a leading zero (i.e. not compressed).
|
||||
func Unpack(data []byte) ([]byte, error) {
|
||||
dataType, data := data[0], data[1:]
|
||||
if 2&dataType > 0 {
|
||||
if decompressor, err := zlib.NewReader(bytes.NewReader(data)); err != nil {
|
||||
return nil, fmt.Errorf("failed to create zlib reader: %w", err)
|
||||
} else if data, err = io.ReadAll(decompressor); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
108
vendor/go.mau.fi/whatsmeow/binary/xml.go
vendored
Normal file
108
vendor/go.mau.fi/whatsmeow/binary/xml.go
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2021 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package binary
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Options to control how Node.XMLString behaves.
|
||||
var (
|
||||
IndentXML = false
|
||||
MaxBytesToPrintAsHex = 128
|
||||
)
|
||||
|
||||
// XMLString converts the Node to its XML representation
|
||||
func (n *Node) XMLString() string {
|
||||
content := n.contentString()
|
||||
if len(content) == 0 {
|
||||
return fmt.Sprintf("<%[1]s%[2]s/>", n.Tag, n.attributeString())
|
||||
}
|
||||
newline := "\n"
|
||||
if len(content) == 1 || !IndentXML {
|
||||
newline = ""
|
||||
}
|
||||
return fmt.Sprintf("<%[1]s%[2]s>%[4]s%[3]s%[4]s</%[1]s>", n.Tag, n.attributeString(), strings.Join(content, newline), newline)
|
||||
}
|
||||
|
||||
func (n *Node) attributeString() string {
|
||||
if len(n.Attrs) == 0 {
|
||||
return ""
|
||||
}
|
||||
stringAttrs := make([]string, len(n.Attrs)+1)
|
||||
i := 1
|
||||
for key, value := range n.Attrs {
|
||||
stringAttrs[i] = fmt.Sprintf(`%s="%v"`, key, value)
|
||||
i++
|
||||
}
|
||||
sort.Strings(stringAttrs)
|
||||
return strings.Join(stringAttrs, " ")
|
||||
}
|
||||
|
||||
func printable(data []byte) string {
|
||||
if !utf8.Valid(data) {
|
||||
return ""
|
||||
}
|
||||
str := string(data)
|
||||
for _, c := range str {
|
||||
if !unicode.IsPrint(c) {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func (n *Node) contentString() []string {
|
||||
split := make([]string, 0)
|
||||
switch content := n.Content.(type) {
|
||||
case []Node:
|
||||
for _, item := range content {
|
||||
split = append(split, strings.Split(item.XMLString(), "\n")...)
|
||||
}
|
||||
case []byte:
|
||||
if strContent := printable(content); len(strContent) > 0 {
|
||||
if IndentXML {
|
||||
split = append(split, strings.Split(string(content), "\n")...)
|
||||
} else {
|
||||
split = append(split, strings.ReplaceAll(string(content), "\n", "\\n"))
|
||||
}
|
||||
} else if len(content) > MaxBytesToPrintAsHex {
|
||||
split = append(split, fmt.Sprintf("<!-- %d bytes -->", len(content)))
|
||||
} else if !IndentXML {
|
||||
split = append(split, hex.EncodeToString(content))
|
||||
} else {
|
||||
hexData := hex.EncodeToString(content)
|
||||
for i := 0; i < len(hexData); i += 80 {
|
||||
if len(hexData) < i+80 {
|
||||
split = append(split, hexData[i:])
|
||||
} else {
|
||||
split = append(split, hexData[i:i+80])
|
||||
}
|
||||
}
|
||||
}
|
||||
case nil:
|
||||
// don't append anything
|
||||
default:
|
||||
strContent := fmt.Sprintf("%s", content)
|
||||
if IndentXML {
|
||||
split = append(split, strings.Split(strContent, "\n")...)
|
||||
} else {
|
||||
split = append(split, strings.ReplaceAll(strContent, "\n", "\\n"))
|
||||
}
|
||||
}
|
||||
if len(split) > 1 && IndentXML {
|
||||
for i, line := range split {
|
||||
split[i] = " " + line
|
||||
}
|
||||
}
|
||||
return split
|
||||
}
|
Reference in New Issue
Block a user