mirror of
https://github.com/42wim/matterbridge.git
synced 2024-11-22 03:49:25 +01:00
Update Rhymen/go-whatsapp vendor (#876)
This commit is contained in:
parent
921f2dfcdf
commit
d525f1c9e4
2
go.mod
2
go.mod
@ -5,7 +5,7 @@ require (
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
|
||||
github.com/Jeffail/gabs v1.1.1 // indirect
|
||||
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329
|
||||
github.com/Rhymen/go-whatsapp v0.0.2
|
||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a
|
||||
github.com/bwmarrin/discordgo v0.19.0
|
||||
github.com/d5/tengo v1.24.1
|
||||
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
|
||||
|
4
go.sum
4
go.sum
@ -11,8 +11,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
|
||||
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329 h1:xZBoq249G9MSt+XuY7sVQzcfONJ6IQuwpCK+KAaOpnY=
|
||||
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg=
|
||||
github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
|
||||
github.com/Rhymen/go-whatsapp v0.0.2 h1:MelwdquHuuNObBGV7CpXbky2aVdilx/CwiXMwZvS74U=
|
||||
github.com/Rhymen/go-whatsapp v0.0.2/go.mod h1:qf/2PQi82Okxw/igghu/oMGzTeUYuKBq1JNo3tdQyNg=
|
||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a h1:umvfZW+YE+ynhYwsyheyunB/3xRK68kNFMRNUMQxzJI=
|
||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a/go.mod h1:qf/2PQi82Okxw/igghu/oMGzTeUYuKBq1JNo3tdQyNg=
|
||||
github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:zgCiQtBtZ4P4gFWvwl9aashsdwOcbb/EHOGRmSzM8ME=
|
||||
github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU=
|
||||
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw=
|
||||
|
10
vendor/github.com/Rhymen/go-whatsapp/README.md
generated
vendored
10
vendor/github.com/Rhymen/go-whatsapp/README.md
generated
vendored
@ -50,17 +50,25 @@ func (myHandler) HandleImageMessage(message whatsapp.ImageMessage) {
|
||||
fmt.Println(message)
|
||||
}
|
||||
|
||||
func (myHandler) HandleDocumentMessage(message whatsapp.DocumentMessage) {
|
||||
fmt.Println(message)
|
||||
}
|
||||
|
||||
func (myHandler) HandleVideoMessage(message whatsapp.VideoMessage) {
|
||||
fmt.Println(message)
|
||||
}
|
||||
|
||||
func (myHandler) HandleAudioMessage(message whatsapp.AudioMessage){
|
||||
fmt.Println(message)
|
||||
}
|
||||
|
||||
func (myHandler) HandleJsonMessage(message string) {
|
||||
fmt.Println(message)
|
||||
}
|
||||
|
||||
wac.AddHandler(myHandler{})
|
||||
```
|
||||
The message handlers are all optional, you don't need to implement anything but the error handler to implement the interface. The ImageMessage and VideoMessage provide a Download function to get the media data.
|
||||
The message handlers are all optional, you don't need to implement anything but the error handler to implement the interface. The ImageMessage, VideoMessage, AudioMessage and DocumentMessage provide a Download function to get the media data.
|
||||
|
||||
### Sending text messages
|
||||
```go
|
||||
|
183
vendor/github.com/Rhymen/go-whatsapp/chat_history.go
generated
vendored
Normal file
183
vendor/github.com/Rhymen/go-whatsapp/chat_history.go
generated
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
package whatsapp
|
||||
|
||||
import (
|
||||
"github.com/Rhymen/go-whatsapp/binary"
|
||||
"github.com/Rhymen/go-whatsapp/binary/proto"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MessageOffsetInfo struct {
|
||||
FirstMessageId string
|
||||
FirstMessageOwner bool
|
||||
}
|
||||
|
||||
func decodeMessages(n *binary.Node) []*proto.WebMessageInfo {
|
||||
|
||||
var messages = make([]*proto.WebMessageInfo, 0)
|
||||
|
||||
if n == nil || n.Attributes == nil || n.Content == nil {
|
||||
return messages
|
||||
}
|
||||
|
||||
for _, msg := range n.Content.([]interface{}) {
|
||||
switch msg.(type) {
|
||||
case *proto.WebMessageInfo:
|
||||
messages = append(messages, msg.(*proto.WebMessageInfo))
|
||||
default:
|
||||
log.Println("decodeMessages: Non WebMessage encountered")
|
||||
}
|
||||
}
|
||||
|
||||
return messages
|
||||
}
|
||||
|
||||
// LoadChatMessages is useful to "scroll" messages, loading by count at a time
|
||||
// if handlers == nil the func will use default handlers
|
||||
// if after == true LoadChatMessages will load messages after the specified messageId, otherwise it will return
|
||||
// message before the messageId
|
||||
func (wac *Conn) LoadChatMessages(jid string, count int, messageId string, owner bool, after bool, handlers ...Handler) error {
|
||||
if count <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if handlers == nil {
|
||||
handlers = wac.handler
|
||||
}
|
||||
|
||||
kind := "before"
|
||||
if after {
|
||||
kind = "after"
|
||||
}
|
||||
|
||||
node, err := wac.query("message", jid, messageId, kind,
|
||||
strconv.FormatBool(owner), "", count, 0)
|
||||
|
||||
if err != nil {
|
||||
wac.handleWithCustomHandlers(err, handlers)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, msg := range decodeMessages(node) {
|
||||
wac.handleWithCustomHandlers(ParseProtoMessage(msg), handlers)
|
||||
wac.handleWithCustomHandlers(msg, handlers)
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// LoadFullChatHistory loads full chat history for the given jid
|
||||
// chunkSize = how many messages to load with one query; if handlers == nil the func will use default handlers;
|
||||
// pauseBetweenQueries = how much time to sleep between queries
|
||||
func (wac *Conn) LoadFullChatHistory(jid string, chunkSize int,
|
||||
pauseBetweenQueries time.Duration, handlers ...Handler) {
|
||||
if chunkSize <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if handlers == nil {
|
||||
handlers = wac.handler
|
||||
}
|
||||
|
||||
beforeMsg := ""
|
||||
beforeMsgIsOwner := true
|
||||
|
||||
for {
|
||||
node, err := wac.query("message", jid, beforeMsg, "before",
|
||||
strconv.FormatBool(beforeMsgIsOwner), "", chunkSize, 0)
|
||||
|
||||
if err != nil {
|
||||
wac.handleWithCustomHandlers(err, handlers)
|
||||
} else {
|
||||
|
||||
msgs := decodeMessages(node)
|
||||
for _, msg := range msgs {
|
||||
wac.handleWithCustomHandlers(ParseProtoMessage(msg), handlers)
|
||||
wac.handleWithCustomHandlers(msg, handlers)
|
||||
}
|
||||
|
||||
if len(msgs) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
beforeMsg = *msgs[0].Key.Id
|
||||
beforeMsgIsOwner = msgs[0].Key.FromMe != nil && *msgs[0].Key.FromMe
|
||||
}
|
||||
|
||||
<-time.After(pauseBetweenQueries)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// LoadFullChatHistoryAfter loads all messages after the specified messageId
|
||||
// useful to "catch up" with the message history after some specified message
|
||||
func (wac *Conn) LoadFullChatHistoryAfter(jid string, messageId string, chunkSize int,
|
||||
pauseBetweenQueries time.Duration, handlers ...Handler) {
|
||||
|
||||
if chunkSize <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if handlers == nil {
|
||||
handlers = wac.handler
|
||||
}
|
||||
|
||||
msgOwner := true
|
||||
prevNotFound := false
|
||||
|
||||
for {
|
||||
node, err := wac.query("message", jid, messageId, "after",
|
||||
strconv.FormatBool(msgOwner), "", chunkSize, 0)
|
||||
|
||||
if err != nil {
|
||||
|
||||
// Whatsapp will return 404 status when there is wrong owner flag on the requested message id
|
||||
if err == ErrServerRespondedWith404 {
|
||||
|
||||
// this will detect two consecutive "not found" errors.
|
||||
// this is done to prevent infinite loop when wrong message id supplied
|
||||
if prevNotFound {
|
||||
log.Println("LoadFullChatHistoryAfter: could not retrieve any messages, wrong message id?")
|
||||
return
|
||||
}
|
||||
prevNotFound = true
|
||||
|
||||
// try to reverse the owner flag and retry
|
||||
if msgOwner {
|
||||
// reverse initial msgOwner value and retry
|
||||
msgOwner = false
|
||||
|
||||
<-time.After(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if the error isn't a 404 error, pass it to the error handler
|
||||
wac.handleWithCustomHandlers(err, handlers)
|
||||
} else {
|
||||
|
||||
msgs := decodeMessages(node)
|
||||
for _, msg := range msgs {
|
||||
wac.handleWithCustomHandlers(ParseProtoMessage(msg), handlers)
|
||||
wac.handleWithCustomHandlers(msg, handlers)
|
||||
}
|
||||
|
||||
if len(msgs) != chunkSize {
|
||||
break
|
||||
}
|
||||
|
||||
messageId = *msgs[0].Key.Id
|
||||
msgOwner = msgs[0].Key.FromMe != nil && *msgs[0].Key.FromMe
|
||||
}
|
||||
|
||||
// message was found
|
||||
prevNotFound = false
|
||||
|
||||
<-time.After(pauseBetweenQueries)
|
||||
|
||||
}
|
||||
|
||||
}
|
15
vendor/github.com/Rhymen/go-whatsapp/conn.go
generated
vendored
15
vendor/github.com/Rhymen/go-whatsapp/conn.go
generated
vendored
@ -89,6 +89,8 @@ type Conn struct {
|
||||
|
||||
longClientName string
|
||||
shortClientName string
|
||||
|
||||
loginSessionLock sync.RWMutex
|
||||
}
|
||||
|
||||
type websocketWrapper struct {
|
||||
@ -191,6 +193,19 @@ func (wac *Conn) Disconnect() (Session, error) {
|
||||
return *wac.session, err
|
||||
}
|
||||
|
||||
func (wac *Conn) AdminTest() (bool, error) {
|
||||
if !wac.connected {
|
||||
return false, ErrNotConnected
|
||||
}
|
||||
|
||||
if !wac.loggedIn {
|
||||
return false, ErrInvalidSession
|
||||
}
|
||||
|
||||
result, err := wac.sendAdminTest()
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (wac *Conn) keepAlive(minIntervalMs int, maxIntervalMs int) {
|
||||
defer wac.wg.Done()
|
||||
|
||||
|
21
vendor/github.com/Rhymen/go-whatsapp/errors.go
generated
vendored
21
vendor/github.com/Rhymen/go-whatsapp/errors.go
generated
vendored
@ -6,15 +6,18 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrAlreadyConnected = errors.New("already connected")
|
||||
ErrAlreadyLoggedIn = errors.New("already logged in")
|
||||
ErrInvalidSession = errors.New("invalid session")
|
||||
ErrLoginInProgress = errors.New("login or restore already running")
|
||||
ErrNotConnected = errors.New("not connected")
|
||||
ErrInvalidWsData = errors.New("received invalid data")
|
||||
ErrConnectionTimeout = errors.New("connection timed out")
|
||||
ErrMissingMessageTag = errors.New("no messageTag specified or to short")
|
||||
ErrInvalidHmac = errors.New("invalid hmac")
|
||||
ErrAlreadyConnected = errors.New("already connected")
|
||||
ErrAlreadyLoggedIn = errors.New("already logged in")
|
||||
ErrInvalidSession = errors.New("invalid session")
|
||||
ErrLoginInProgress = errors.New("login or restore already running")
|
||||
ErrNotConnected = errors.New("not connected")
|
||||
ErrInvalidWsData = errors.New("received invalid data")
|
||||
ErrInvalidWsState = errors.New("can't handle binary data when not logged in")
|
||||
ErrConnectionTimeout = errors.New("connection timed out")
|
||||
ErrMissingMessageTag = errors.New("no messageTag specified or to short")
|
||||
ErrInvalidHmac = errors.New("invalid hmac")
|
||||
ErrInvalidServerResponse = errors.New("invalid response received from server")
|
||||
ErrServerRespondedWith404 = errors.New("server responded with status 404")
|
||||
)
|
||||
|
||||
type ErrConnectionFailed struct {
|
||||
|
128
vendor/github.com/Rhymen/go-whatsapp/handler.go
generated
vendored
128
vendor/github.com/Rhymen/go-whatsapp/handler.go
generated
vendored
@ -20,6 +20,11 @@ type Handler interface {
|
||||
HandleError(err error)
|
||||
}
|
||||
|
||||
type SyncHandler interface {
|
||||
Handler
|
||||
ShouldCallSynchronously() bool
|
||||
}
|
||||
|
||||
/*
|
||||
The TextMessageHandler interface needs to be implemented to receive text messages dispatched by the dispatcher.
|
||||
*/
|
||||
@ -60,6 +65,22 @@ type DocumentMessageHandler interface {
|
||||
HandleDocumentMessage(message DocumentMessage)
|
||||
}
|
||||
|
||||
/*
|
||||
The LiveLocationMessageHandler interface needs to be implemented to receive live location messages dispatched by the dispatcher.
|
||||
*/
|
||||
type LiveLocationMessageHandler interface {
|
||||
Handler
|
||||
HandleLiveLocationMessage(message LiveLocationMessage)
|
||||
}
|
||||
|
||||
/*
|
||||
The LocationMessageHandler interface needs to be implemented to receive location messages dispatched by the dispatcher.
|
||||
*/
|
||||
type LocationMessageHandler interface {
|
||||
Handler
|
||||
HandleLocationMessage(message LocationMessage)
|
||||
}
|
||||
|
||||
/*
|
||||
The JsonMessageHandler interface needs to be implemented to receive json messages dispatched by the dispatcher.
|
||||
These json messages contain status updates of every kind sent by WhatsAppWeb servers. WhatsAppWeb uses these messages
|
||||
@ -127,52 +148,113 @@ func (wac *Conn) RemoveHandlers() {
|
||||
wac.handler = make([]Handler, 0)
|
||||
}
|
||||
|
||||
func (wac *Conn) shouldCallSynchronously(handler Handler) bool {
|
||||
sh, ok := handler.(SyncHandler)
|
||||
return ok && sh.ShouldCallSynchronously()
|
||||
}
|
||||
|
||||
func (wac *Conn) handle(message interface{}) {
|
||||
wac.handleWithCustomHandlers(message, wac.handler)
|
||||
}
|
||||
|
||||
func (wac *Conn) handleWithCustomHandlers(message interface{}, handlers []Handler) {
|
||||
switch m := message.(type) {
|
||||
case error:
|
||||
for _, h := range wac.handler {
|
||||
go h.HandleError(m)
|
||||
for _, h := range handlers {
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
h.HandleError(m)
|
||||
} else {
|
||||
go h.HandleError(m)
|
||||
}
|
||||
}
|
||||
case string:
|
||||
for _, h := range wac.handler {
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(JsonMessageHandler); ok {
|
||||
go x.HandleJsonMessage(m)
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleJsonMessage(m)
|
||||
} else {
|
||||
go x.HandleJsonMessage(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
case TextMessage:
|
||||
for _, h := range wac.handler {
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(TextMessageHandler); ok {
|
||||
go x.HandleTextMessage(m)
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleTextMessage(m)
|
||||
} else {
|
||||
go x.HandleTextMessage(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
case ImageMessage:
|
||||
for _, h := range wac.handler {
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(ImageMessageHandler); ok {
|
||||
go x.HandleImageMessage(m)
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleImageMessage(m)
|
||||
} else {
|
||||
go x.HandleImageMessage(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
case VideoMessage:
|
||||
for _, h := range wac.handler {
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(VideoMessageHandler); ok {
|
||||
go x.HandleVideoMessage(m)
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleVideoMessage(m)
|
||||
} else {
|
||||
go x.HandleVideoMessage(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
case AudioMessage:
|
||||
for _, h := range wac.handler {
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(AudioMessageHandler); ok {
|
||||
go x.HandleAudioMessage(m)
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleAudioMessage(m)
|
||||
} else {
|
||||
go x.HandleAudioMessage(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
case DocumentMessage:
|
||||
for _, h := range wac.handler {
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(DocumentMessageHandler); ok {
|
||||
go x.HandleDocumentMessage(m)
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleDocumentMessage(m)
|
||||
} else {
|
||||
go x.HandleDocumentMessage(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
case LocationMessage:
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(LocationMessageHandler); ok {
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleLocationMessage(m)
|
||||
} else {
|
||||
go x.HandleLocationMessage(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
case LiveLocationMessage:
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(LiveLocationMessageHandler); ok {
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleLiveLocationMessage(m)
|
||||
} else {
|
||||
go x.HandleLiveLocationMessage(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
case *proto.WebMessageInfo:
|
||||
for _, h := range wac.handler {
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(RawMessageHandler); ok {
|
||||
go x.HandleRawMessage(m)
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleRawMessage(m)
|
||||
} else {
|
||||
go x.HandleRawMessage(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,7 +283,11 @@ func (wac *Conn) handleContacts(contacts interface{}) {
|
||||
}
|
||||
for _, h := range wac.handler {
|
||||
if x, ok := h.(ContactListHandler); ok {
|
||||
go x.HandleContactList(contactList)
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleContactList(contactList)
|
||||
} else {
|
||||
go x.HandleContactList(contactList)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -230,7 +316,11 @@ func (wac *Conn) handleChats(chats interface{}) {
|
||||
}
|
||||
for _, h := range wac.handler {
|
||||
if x, ok := h.(ChatListHandler); ok {
|
||||
go x.HandleChatList(chatList)
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleChatList(chatList)
|
||||
} else {
|
||||
go x.HandleChatList(chatList)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -247,7 +337,7 @@ func (wac *Conn) dispatch(msg interface{}) {
|
||||
for a := range con {
|
||||
if v, ok := con[a].(*proto.WebMessageInfo); ok {
|
||||
wac.handle(v)
|
||||
wac.handle(parseProtoMessage(v))
|
||||
wac.handle(ParseProtoMessage(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
vendor/github.com/Rhymen/go-whatsapp/media.go
generated
vendored
12
vendor/github.com/Rhymen/go-whatsapp/media.go
generated
vendored
@ -8,8 +8,6 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Rhymen/go-whatsapp/crypto/cbc"
|
||||
"github.com/Rhymen/go-whatsapp/crypto/hkdf"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
@ -17,6 +15,9 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp/crypto/cbc"
|
||||
"github.com/Rhymen/go-whatsapp/crypto/hkdf"
|
||||
)
|
||||
|
||||
func Download(url string, mediaKey []byte, appInfo MediaType, fileLength int) ([]byte, error) {
|
||||
@ -73,17 +74,18 @@ func downloadMedia(url string) (file []byte, mac []byte, err error) {
|
||||
return nil, nil, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, nil, fmt.Errorf("download failed")
|
||||
return nil, nil, fmt.Errorf("download failed with status code %d", resp.StatusCode)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.ContentLength <= 10 {
|
||||
return nil, nil, fmt.Errorf("file to short")
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
n := len(data)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := len(data)
|
||||
return data[:n-10], data[n-10 : n], nil
|
||||
}
|
||||
|
||||
@ -142,7 +144,7 @@ func (wac *Conn) Upload(reader io.Reader, appInfo MediaType) (url string, mediaK
|
||||
select {
|
||||
case r := <-ch:
|
||||
if err = json.Unmarshal([]byte(r), &resp); err != nil {
|
||||
return "", nil, nil, nil, 0, fmt.Errorf("error decoding upload response: %v\n", err)
|
||||
return "", nil, nil, nil, 0, fmt.Errorf("error decoding upload response: %v", err)
|
||||
}
|
||||
case <-time.After(wac.msgTimeout):
|
||||
return "", nil, nil, nil, 0, fmt.Errorf("restore session init timed out")
|
||||
|
107
vendor/github.com/Rhymen/go-whatsapp/message.go
generated
vendored
107
vendor/github.com/Rhymen/go-whatsapp/message.go
generated
vendored
@ -68,6 +68,14 @@ func (wac *Conn) Send(msg interface{}) (string, error) {
|
||||
msgProto = getAudioProto(m)
|
||||
msgInfo = getMessageInfo(msgProto)
|
||||
ch, err = wac.sendProto(msgProto)
|
||||
case LocationMessage:
|
||||
msgProto = GetLocationProto(m)
|
||||
msgInfo = getMessageInfo(msgProto)
|
||||
ch, err = wac.sendProto(msgProto)
|
||||
case LiveLocationMessage:
|
||||
msgProto = GetLiveLocationProto(m)
|
||||
msgInfo = getMessageInfo(msgProto)
|
||||
ch, err = wac.sendProto(msgProto)
|
||||
default:
|
||||
return "ERROR", fmt.Errorf("cannot match type %T, use message types declared in the package", msg)
|
||||
}
|
||||
@ -269,6 +277,7 @@ type VideoMessage struct {
|
||||
Length uint32
|
||||
Type string
|
||||
Content io.Reader
|
||||
GifPlayback bool
|
||||
url string
|
||||
mediaKey []byte
|
||||
fileEncSha256 []byte
|
||||
@ -282,6 +291,7 @@ func getVideoMessage(msg *proto.WebMessageInfo) VideoMessage {
|
||||
Info: getMessageInfo(msg),
|
||||
Caption: vid.GetCaption(),
|
||||
Thumbnail: vid.GetJpegThumbnail(),
|
||||
GifPlayback: vid.GetGifPlayback(),
|
||||
url: vid.GetUrl(),
|
||||
mediaKey: vid.GetMediaKey(),
|
||||
Length: vid.GetSeconds(),
|
||||
@ -299,6 +309,7 @@ func getVideoProto(msg VideoMessage) *proto.WebMessageInfo {
|
||||
Caption: &msg.Caption,
|
||||
JpegThumbnail: msg.Thumbnail,
|
||||
Url: &msg.url,
|
||||
GifPlayback: &msg.GifPlayback,
|
||||
MediaKey: msg.mediaKey,
|
||||
Seconds: &msg.Length,
|
||||
FileEncSha256: msg.fileEncSha256,
|
||||
@ -431,7 +442,95 @@ func (m *DocumentMessage) Download() ([]byte, error) {
|
||||
return Download(m.url, m.mediaKey, MediaDocument, int(m.fileLength))
|
||||
}
|
||||
|
||||
func parseProtoMessage(msg *proto.WebMessageInfo) interface{} {
|
||||
/*
|
||||
LocationMessage represents a location message
|
||||
*/
|
||||
type LocationMessage struct {
|
||||
Info MessageInfo
|
||||
DegreesLatitude float64
|
||||
DegreesLongitude float64
|
||||
Name string
|
||||
Address string
|
||||
Url string
|
||||
JpegThumbnail []byte
|
||||
}
|
||||
|
||||
func GetLocationMessage(msg *proto.WebMessageInfo) LocationMessage {
|
||||
loc := msg.GetMessage().GetLocationMessage()
|
||||
return LocationMessage{
|
||||
Info: getMessageInfo(msg),
|
||||
DegreesLatitude: loc.GetDegreesLatitude(),
|
||||
DegreesLongitude: loc.GetDegreesLongitude(),
|
||||
Name: loc.GetName(),
|
||||
Address: loc.GetAddress(),
|
||||
Url: loc.GetUrl(),
|
||||
JpegThumbnail: loc.GetJpegThumbnail(),
|
||||
}
|
||||
}
|
||||
|
||||
func GetLocationProto(msg LocationMessage) *proto.WebMessageInfo {
|
||||
p := getInfoProto(&msg.Info)
|
||||
p.Message = &proto.Message{
|
||||
LocationMessage: &proto.LocationMessage{
|
||||
DegreesLatitude: &msg.DegreesLatitude,
|
||||
DegreesLongitude: &msg.DegreesLongitude,
|
||||
Name: &msg.Name,
|
||||
Address: &msg.Address,
|
||||
Url: &msg.Url,
|
||||
JpegThumbnail: msg.JpegThumbnail,
|
||||
},
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
/*
|
||||
LiveLocationMessage represents a live location message
|
||||
*/
|
||||
type LiveLocationMessage struct {
|
||||
Info MessageInfo
|
||||
DegreesLatitude float64
|
||||
DegreesLongitude float64
|
||||
AccuracyInMeters uint32
|
||||
SpeedInMps float32
|
||||
DegreesClockwiseFromMagneticNorth uint32
|
||||
Caption string
|
||||
SequenceNumber int64
|
||||
JpegThumbnail []byte
|
||||
}
|
||||
|
||||
func GetLiveLocationMessage(msg *proto.WebMessageInfo) LiveLocationMessage {
|
||||
loc := msg.GetMessage().GetLiveLocationMessage()
|
||||
return LiveLocationMessage{
|
||||
Info: getMessageInfo(msg),
|
||||
DegreesLatitude: loc.GetDegreesLatitude(),
|
||||
DegreesLongitude: loc.GetDegreesLongitude(),
|
||||
AccuracyInMeters: loc.GetAccuracyInMeters(),
|
||||
SpeedInMps: loc.GetSpeedInMps(),
|
||||
DegreesClockwiseFromMagneticNorth: loc.GetDegreesClockwiseFromMagneticNorth(),
|
||||
Caption: loc.GetCaption(),
|
||||
SequenceNumber: loc.GetSequenceNumber(),
|
||||
JpegThumbnail: loc.GetJpegThumbnail(),
|
||||
}
|
||||
}
|
||||
|
||||
func GetLiveLocationProto(msg LiveLocationMessage) *proto.WebMessageInfo {
|
||||
p := getInfoProto(&msg.Info)
|
||||
p.Message = &proto.Message{
|
||||
LiveLocationMessage: &proto.LiveLocationMessage{
|
||||
DegreesLatitude: &msg.DegreesLatitude,
|
||||
DegreesLongitude: &msg.DegreesLongitude,
|
||||
AccuracyInMeters: &msg.AccuracyInMeters,
|
||||
SpeedInMps: &msg.SpeedInMps,
|
||||
DegreesClockwiseFromMagneticNorth: &msg.DegreesClockwiseFromMagneticNorth,
|
||||
Caption: &msg.Caption,
|
||||
SequenceNumber: &msg.SequenceNumber,
|
||||
JpegThumbnail: msg.JpegThumbnail,
|
||||
},
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func ParseProtoMessage(msg *proto.WebMessageInfo) interface{} {
|
||||
switch {
|
||||
|
||||
case msg.GetMessage().GetAudioMessage() != nil:
|
||||
@ -452,6 +551,12 @@ func parseProtoMessage(msg *proto.WebMessageInfo) interface{} {
|
||||
case msg.GetMessage().GetExtendedTextMessage() != nil:
|
||||
return getTextMessage(msg)
|
||||
|
||||
case msg.GetMessage().GetLocationMessage() != nil:
|
||||
return GetLocationMessage(msg)
|
||||
|
||||
case msg.GetMessage().GetLiveLocationMessage() != nil:
|
||||
return GetLiveLocationMessage(msg)
|
||||
|
||||
default:
|
||||
//cannot match message
|
||||
}
|
||||
|
25
vendor/github.com/Rhymen/go-whatsapp/read.go
generated
vendored
25
vendor/github.com/Rhymen/go-whatsapp/read.go
generated
vendored
@ -3,6 +3,8 @@ package whatsapp
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Rhymen/go-whatsapp/binary"
|
||||
"github.com/Rhymen/go-whatsapp/crypto/cbc"
|
||||
"github.com/gorilla/websocket"
|
||||
@ -75,7 +77,13 @@ func (wac *Conn) processReadData(msgType int, msg []byte) error {
|
||||
wac.listener.Lock()
|
||||
delete(wac.listener.m, data[0])
|
||||
wac.listener.Unlock()
|
||||
} else if msgType == websocket.BinaryMessage && wac.loggedIn {
|
||||
} else if msgType == websocket.BinaryMessage {
|
||||
wac.loginSessionLock.RLock()
|
||||
sess := wac.session
|
||||
wac.loginSessionLock.RUnlock()
|
||||
if sess == nil || sess.MacKey == nil || sess.EncKey == nil {
|
||||
return ErrInvalidWsState
|
||||
}
|
||||
message, err := wac.decryptBinaryMessage([]byte(data[1]))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error decoding binary")
|
||||
@ -90,6 +98,21 @@ func (wac *Conn) processReadData(msgType int, msg []byte) error {
|
||||
func (wac *Conn) decryptBinaryMessage(msg []byte) (*binary.Node, error) {
|
||||
//message validation
|
||||
h2 := hmac.New(sha256.New, wac.session.MacKey)
|
||||
if len(msg) < 33 {
|
||||
var response struct {
|
||||
Status int `json:"status"`
|
||||
}
|
||||
err := json.Unmarshal(msg, &response)
|
||||
if err == nil {
|
||||
if response.Status == 404 {
|
||||
return nil, ErrServerRespondedWith404
|
||||
}
|
||||
return nil, errors.New(fmt.Sprintf("server responded with %d", response.Status))
|
||||
} else {
|
||||
return nil, ErrInvalidServerResponse
|
||||
}
|
||||
|
||||
}
|
||||
h2.Write([]byte(msg[32:]))
|
||||
if !hmac.Equal(h2.Sum(nil), msg[:32]) {
|
||||
return nil, ErrInvalidHmac
|
||||
|
10
vendor/github.com/Rhymen/go-whatsapp/session.go
generated
vendored
10
vendor/github.com/Rhymen/go-whatsapp/session.go
generated
vendored
@ -100,6 +100,14 @@ func (wac *Conn) SetClientName(long, short string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
SetClientVersion sets WhatsApp client version
|
||||
Default value is 0.3.3324
|
||||
*/
|
||||
func (wac *Conn) SetClientVersion(major int, minor int, patch int) {
|
||||
waVersion = []int{major, minor, patch}
|
||||
}
|
||||
|
||||
/*
|
||||
Login is the function that creates a new whatsapp session and logs you in. If you do not want to scan the qr code
|
||||
every time, you should save the returned session and use RestoreWithSession the next time. Login takes a writable channel
|
||||
@ -187,6 +195,8 @@ func (wac *Conn) Login(qrChan chan<- string) (Session, error) {
|
||||
var resp2 []interface{}
|
||||
select {
|
||||
case r1 := <-s1:
|
||||
wac.loginSessionLock.Lock()
|
||||
defer wac.loginSessionLock.Unlock()
|
||||
if err := json.Unmarshal([]byte(r1), &resp2); err != nil {
|
||||
return session, fmt.Errorf("error decoding qr code resp: %v", err)
|
||||
}
|
||||
|
30
vendor/github.com/Rhymen/go-whatsapp/write.go
generated
vendored
30
vendor/github.com/Rhymen/go-whatsapp/write.go
generated
vendored
@ -78,6 +78,36 @@ func (wac *Conn) sendKeepAlive() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
When phone is unreachable, WhatsAppWeb sends ["admin","test"] time after time to try a successful contact.
|
||||
Tested with Airplane mode and no connection at all.
|
||||
*/
|
||||
func (wac *Conn) sendAdminTest() (bool, error) {
|
||||
data := []interface{}{"admin", "test"}
|
||||
|
||||
r, err := wac.writeJson(data)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "error sending admin test")
|
||||
}
|
||||
|
||||
var response []interface{}
|
||||
|
||||
select {
|
||||
case resp := <-r:
|
||||
if err := json.Unmarshal([]byte(resp), &response); err != nil {
|
||||
return false, fmt.Errorf("error decoding response message: %v\n", err)
|
||||
}
|
||||
case <-time.After(wac.msgTimeout):
|
||||
return false, ErrConnectionTimeout
|
||||
}
|
||||
|
||||
if len(response) == 2 && response[0].(string) == "Pong" && response[1].(bool) == true {
|
||||
return true, nil
|
||||
} else{
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (wac *Conn) write(messageType int, answerMessageTag string, data []byte) (<-chan string, error) {
|
||||
var ch chan string
|
||||
if answerMessageTag != "" {
|
||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -15,7 +15,7 @@ github.com/Philipp15b/go-steam/protocol/gamecoordinator
|
||||
github.com/Philipp15b/go-steam/protocol/protobuf
|
||||
github.com/Philipp15b/go-steam/rwu
|
||||
github.com/Philipp15b/go-steam/socialcache
|
||||
# github.com/Rhymen/go-whatsapp v0.0.2
|
||||
# github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a
|
||||
github.com/Rhymen/go-whatsapp
|
||||
github.com/Rhymen/go-whatsapp/binary
|
||||
github.com/Rhymen/go-whatsapp/binary/proto
|
||||
|
Loading…
Reference in New Issue
Block a user