From ce7b749fd54be871ce62934fca7978b165809e87 Mon Sep 17 00:00:00 2001 From: Wim Date: Thu, 13 Jun 2019 22:37:31 +0200 Subject: Update github.com/Rhymen/go-whatsapp vendor. Fixes #843 --- vendor/github.com/Rhymen/go-whatsapp/README.md | 2 +- .../Rhymen/go-whatsapp/crypto/hkdf/hkdf.go | 49 +++++++------- vendor/github.com/Rhymen/go-whatsapp/go.mod | 4 ++ vendor/github.com/Rhymen/go-whatsapp/go.sum | 21 ++++++ vendor/github.com/Rhymen/go-whatsapp/handler.go | 77 ++++++++++++++++++++++ vendor/github.com/Rhymen/go-whatsapp/message.go | 48 +++++++++----- vendor/github.com/Rhymen/go-whatsapp/session.go | 16 +++-- vendor/github.com/Rhymen/go-whatsapp/store.go | 35 ++++++++++ vendor/modules.txt | 2 +- 9 files changed, 202 insertions(+), 52 deletions(-) (limited to 'vendor') diff --git a/vendor/github.com/Rhymen/go-whatsapp/README.md b/vendor/github.com/Rhymen/go-whatsapp/README.md index 54024de8..b90d2991 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/README.md +++ b/vendor/github.com/Rhymen/go-whatsapp/README.md @@ -30,7 +30,7 @@ The authentication process requires you to scan the qr code, that is send throug ### Restore ```go -newSess, err := wac.RestoreSession(sess) +newSess, err := wac.RestoreWithSession(sess) ``` The restore function needs a valid session and returns the new session that was created. diff --git a/vendor/github.com/Rhymen/go-whatsapp/crypto/hkdf/hkdf.go b/vendor/github.com/Rhymen/go-whatsapp/crypto/hkdf/hkdf.go index e0be0587..3d7361f0 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/crypto/hkdf/hkdf.go +++ b/vendor/github.com/Rhymen/go-whatsapp/crypto/hkdf/hkdf.go @@ -9,7 +9,6 @@ second stage "expands" this key into several additional pseudorandom keys (the o package hkdf import ( - "crypto/hmac" "crypto/sha256" "fmt" "golang.org/x/crypto/hkdf" @@ -20,33 +19,29 @@ import ( Expand expands a given key with the HKDF algorithm. */ func Expand(key []byte, length int, info string) ([]byte, error) { + var h io.Reader if info == "" { - keyBlock := hmac.New(sha256.New, key) - var out, last []byte - - var blockIndex byte = 1 - for i := 0; len(out) < length; i++ { - keyBlock.Reset() - //keyBlock.Write(append(append(last, []byte(info)...), blockIndex)) - keyBlock.Write(last) - keyBlock.Write([]byte(info)) - keyBlock.Write([]byte{blockIndex}) - last = keyBlock.Sum(nil) - blockIndex += 1 - out = append(out, last...) - } - return out[:length], nil + /* + Only used during initial login + Pseudorandom Key is provided by server and has not to be created + */ + h = hkdf.Expand(sha256.New, key, []byte(info)) } else { - h := hkdf.New(sha256.New, key, nil, []byte(info)) - out := make([]byte, length) - n, err := io.ReadAtLeast(h, out, length) - if err != nil { - return nil, err - } - if n != length { - return nil, fmt.Errorf("new key to short") - } - - return out[:length], nil + /* + Used every other time + Pseudorandom Key is created during kdf.New + This is the normal that crypto/hkdf is used + */ + h = hkdf.New(sha256.New, key, nil, []byte(info)) + } + out := make([]byte, length) + n, err := io.ReadAtLeast(h, out, length) + if err != nil { + return nil, err } + if n != length { + return nil, fmt.Errorf("new key to short") + } + + return out, nil } diff --git a/vendor/github.com/Rhymen/go-whatsapp/go.mod b/vendor/github.com/Rhymen/go-whatsapp/go.mod index bb071013..ead71f94 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/go.mod +++ b/vendor/github.com/Rhymen/go-whatsapp/go.mod @@ -1,6 +1,10 @@ module github.com/Rhymen/go-whatsapp require ( + github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d // indirect + github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d // indirect + github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d // indirect + github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d // indirect github.com/golang/protobuf v1.3.0 github.com/gorilla/websocket v1.4.0 github.com/pkg/errors v0.8.1 diff --git a/vendor/github.com/Rhymen/go-whatsapp/go.sum b/vendor/github.com/Rhymen/go-whatsapp/go.sum index 45c18cd7..9cd2a6d6 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/go.sum +++ b/vendor/github.com/Rhymen/go-whatsapp/go.sum @@ -1,14 +1,35 @@ +github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f h1:2dk3eOnYllh+wUOuDhOoC2vUVoJF/5z478ryJ+wzEII= +github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/go.mod h1:4a58ifQTEe2uwwsaqbh3i2un5/CBPg+At/qHpt18Tmk= +github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA= +github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d h1:m3wkrunHupL9XzzM+JZu1pgoDV1d9LFtD0gedNTHVDU= +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 h1:muQlzqfZxjptOBjPdv+UoxVMr8Y1rPx7VMGPJIAFc5w= +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 h1:xP//3V77YvHd1cj2Z3ttuQWAvs5WmIwBbjKe/t0g/tM= +github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw= +github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d h1:IRmRE0SPMByczwE2dhnTcVojje3w2TCSKwFrboLUbDg= +github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE= +github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo= +golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= diff --git a/vendor/github.com/Rhymen/go-whatsapp/handler.go b/vendor/github.com/Rhymen/go-whatsapp/handler.go index 7abd55f3..f909bed5 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/handler.go +++ b/vendor/github.com/Rhymen/go-whatsapp/handler.go @@ -3,6 +3,7 @@ package whatsapp import ( "fmt" "os" + "strings" "github.com/Rhymen/go-whatsapp/binary" "github.com/Rhymen/go-whatsapp/binary/proto" @@ -79,6 +80,22 @@ type RawMessageHandler interface { HandleRawMessage(message *proto.WebMessageInfo) } +/** +The ContactListHandler interface needs to be implemented to applky custom actions to contact lists dispatched by the dispatcher. +*/ +type ContactListHandler interface { + Handler + HandleContactList(contacts []Contact) +} + +/** +The ChatListHandler interface needs to be implemented to apply custom actions to chat lists dispatched by the dispatcher. +*/ +type ChatListHandler interface { + Handler + HandleChatList(contacts []Chat) +} + /* AddHandler adds an handler to the list of handler that receive dispatched messages. The provided handler must at least implement the Handler interface. Additionally implemented @@ -162,6 +179,62 @@ func (wac *Conn) handle(message interface{}) { } +func (wac *Conn) handleContacts(contacts interface{}) { + var contactList []Contact + c, ok := contacts.([]interface{}) + if !ok { + return + } + for _, contact := range c { + contactNode, ok := contact.(binary.Node) + if !ok { + continue + } + + jid := strings.Replace(contactNode.Attributes["jid"], "@c.us", "@s.whatsapp.net", 1) + contactList = append(contactList, Contact{ + jid, + contactNode.Attributes["notify"], + contactNode.Attributes["name"], + contactNode.Attributes["short"], + }) + } + for _, h := range wac.handler { + if x, ok := h.(ContactListHandler); ok { + go x.HandleContactList(contactList) + } + } +} + +func (wac *Conn) handleChats(chats interface{}) { + var chatList []Chat + c, ok := chats.([]interface{}) + if !ok { + return + } + for _, chat := range c { + chatNode, ok := chat.(binary.Node) + if !ok { + continue + } + + jid := strings.Replace(chatNode.Attributes["jid"], "@c.us", "@s.whatsapp.net", 1) + chatList = append(chatList, Chat{ + jid, + chatNode.Attributes["name"], + chatNode.Attributes["count"], + chatNode.Attributes["t"], + chatNode.Attributes["mute"], + chatNode.Attributes["spam"], + }) + } + for _, h := range wac.handler { + if x, ok := h.(ChatListHandler); ok { + go x.HandleChatList(chatList) + } + } +} + func (wac *Conn) dispatch(msg interface{}) { if msg == nil { return @@ -180,6 +253,10 @@ func (wac *Conn) dispatch(msg interface{}) { } } else if message.Description == "response" && message.Attributes["type"] == "contacts" { wac.updateContacts(message.Content) + wac.handleContacts(message.Content) + } else if message.Description == "response" && message.Attributes["type"] == "chat" { + wac.updateChats(message.Content) + wac.handleChats(message.Content) } case error: wac.handle(message) diff --git a/vendor/github.com/Rhymen/go-whatsapp/message.go b/vendor/github.com/Rhymen/go-whatsapp/message.go index 21347361..9d44fb1e 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/message.go +++ b/vendor/github.com/Rhymen/go-whatsapp/message.go @@ -22,61 +22,77 @@ const ( MediaDocument MediaType = "WhatsApp Document Keys" ) -func (wac *Conn) Send(msg interface{}) error { +var msgInfo MessageInfo + +func (wac *Conn) Send(msg interface{}) (string, error) { var err error var ch <-chan string + var msgProto *proto.WebMessageInfo switch m := msg.(type) { case *proto.WebMessageInfo: ch, err = wac.sendProto(m) case TextMessage: - ch, err = wac.sendProto(getTextProto(m)) + msgProto = getTextProto(m) + msgInfo = getMessageInfo(msgProto) + ch, err = wac.sendProto(msgProto) case ImageMessage: m.url, m.mediaKey, m.fileEncSha256, m.fileSha256, m.fileLength, err = wac.Upload(m.Content, MediaImage) if err != nil { - return fmt.Errorf("image upload failed: %v", err) + return "ERROR", fmt.Errorf("image upload failed: %v", err) } - ch, err = wac.sendProto(getImageProto(m)) + msgProto = getImageProto(m) + msgInfo = getMessageInfo(msgProto) + ch, err = wac.sendProto(msgProto) case VideoMessage: m.url, m.mediaKey, m.fileEncSha256, m.fileSha256, m.fileLength, err = wac.Upload(m.Content, MediaVideo) if err != nil { - return fmt.Errorf("video upload failed: %v", err) + return "ERROR", fmt.Errorf("video upload failed: %v", err) } - ch, err = wac.sendProto(getVideoProto(m)) + msgProto = getVideoProto(m) + msgInfo = getMessageInfo(msgProto) + ch, err = wac.sendProto(msgProto) case DocumentMessage: m.url, m.mediaKey, m.fileEncSha256, m.fileSha256, m.fileLength, err = wac.Upload(m.Content, MediaDocument) if err != nil { - return fmt.Errorf("document upload failed: %v", err) + return "ERROR", fmt.Errorf("document upload failed: %v", err) } - ch, err = wac.sendProto(getDocumentProto(m)) + msgProto = getDocumentProto(m) + msgInfo = getMessageInfo(msgProto) + ch, err = wac.sendProto(msgProto) case AudioMessage: m.url, m.mediaKey, m.fileEncSha256, m.fileSha256, m.fileLength, err = wac.Upload(m.Content, MediaAudio) if err != nil { - return fmt.Errorf("audio upload failed: %v", err) + return "ERROR", fmt.Errorf("audio upload failed: %v", err) } - ch, err = wac.sendProto(getAudioProto(m)) + msgProto = getAudioProto(m) + msgInfo = getMessageInfo(msgProto) + ch, err = wac.sendProto(msgProto) default: - return fmt.Errorf("cannot match type %T, use message types declared in the package", msg) + return "ERROR", fmt.Errorf("cannot match type %T, use message types declared in the package", msg) } if err != nil { - return fmt.Errorf("could not send proto: %v", err) + return "ERROR", fmt.Errorf("could not send proto: %v", err) } select { case response := <-ch: var resp map[string]interface{} if err = json.Unmarshal([]byte(response), &resp); err != nil { - return fmt.Errorf("error decoding sending response: %v\n", err) + return "ERROR", fmt.Errorf("error decoding sending response: %v\n", err) } if int(resp["status"].(float64)) != 200 { - return fmt.Errorf("message sending responded with %d", resp["status"]) + return "ERROR", fmt.Errorf("message sending responded with %d", resp["status"]) + } + if int(resp["status"].(float64)) == 200 { + return msgInfo.Id, nil } case <-time.After(wac.msgTimeout): - return fmt.Errorf("sending message timed out") + return "ERROR", fmt.Errorf("sending message timed out") } - return nil + return "ERROR", nil } func (wac *Conn) sendProto(p *proto.WebMessageInfo) (<-chan string, error) { diff --git a/vendor/github.com/Rhymen/go-whatsapp/session.go b/vendor/github.com/Rhymen/go-whatsapp/session.go index b769ef5a..3b9ba235 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/session.go +++ b/vendor/github.com/Rhymen/go-whatsapp/session.go @@ -15,9 +15,12 @@ import ( "github.com/Rhymen/go-whatsapp/crypto/hkdf" ) +//represents the WhatsAppWeb client version +var waVersion = []int{0, 3, 3324} + /* Session contains session individual information. To be able to resume the connection without scanning the qr code -every time you should save the Session returned by Login and use RestoreSession the next time you want to login. +every time you should save the Session returned by Login and use RestoreWithSession the next time you want to login. Every successful created connection returns a new Session. The Session(ClientToken, ServerToken) is altered after every re-login and should be saved every time. */ @@ -99,7 +102,7 @@ func (wac *Conn) SetClientName(long, short string) error { /* 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 RestoreSession the next time. Login takes a writable channel +every time, you should save the returned session and use RestoreWithSession the next time. Login takes a writable channel as an parameter. This channel is used to push the data represented by the qr code back to the user. The received data should be displayed as an qr code in a way you prefer. To print a qr code to console you can use: github.com/Baozisoftware/qrcode-terminal-go Example login procedure: @@ -148,8 +151,7 @@ func (wac *Conn) Login(qrChan chan<- string) (Session, error) { } session.ClientId = base64.StdEncoding.EncodeToString(clientId) - //oldVersion=8691 - login := []interface{}{"admin", "init", []int{0, 3, 225}, []string{wac.longClientName, wac.shortClientName}, session.ClientId, true} + login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName}, session.ClientId, true} loginChan, err := wac.writeJson(login) if err != nil { return session, fmt.Errorf("error writing login: %v\n", err) @@ -272,7 +274,7 @@ func (wac *Conn) RestoreWithSession(session Session) (_ Session, err error) { } /*//TODO: GoDoc -RestoreSession is the function that restores a given session. It will try to reestablish the connection to the +RestoreWithSession is the function that restores a given session. It will try to reestablish the connection to the WhatsAppWeb servers with the provided session. If it succeeds it will return a new session. This new session has to be saved because the Client and Server-Token will change after every login. Logging in with old tokens is possible, but not suggested. If so, a challenge has to be resolved which is just another possible point of failure. @@ -303,7 +305,7 @@ func (wac *Conn) Restore() error { wac.listener.Unlock() //admin init - init := []interface{}{"admin", "init", []int{0, 3, 225}, []string{wac.longClientName, wac.shortClientName}, wac.session.ClientId, true} + init := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName}, wac.session.ClientId, true} initChan, err := wac.writeJson(init) if err != nil { return fmt.Errorf("error writing admin init: %v\n", err) @@ -338,7 +340,7 @@ func (wac *Conn) Restore() error { return fmt.Errorf("error decoding s1 message: %v\n", err) } case <-time.After(wac.msgTimeout): - + //check for an error message select { case r := <-loginChan: diff --git a/vendor/github.com/Rhymen/go-whatsapp/store.go b/vendor/github.com/Rhymen/go-whatsapp/store.go index b1c46e4a..994d0581 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/store.go +++ b/vendor/github.com/Rhymen/go-whatsapp/store.go @@ -7,6 +7,7 @@ import ( type Store struct { Contacts map[string]Contact + Chats map[string]Chat } type Contact struct { @@ -16,9 +17,19 @@ type Contact struct { Short string } +type Chat struct { + Jid string + Name string + Unread string + LastMessageTime string + IsMuted string + IsMarkedSpam string +} + func newStore() *Store { return &Store{ make(map[string]Contact), + make(map[string]Chat), } } @@ -43,3 +54,27 @@ func (wac *Conn) updateContacts(contacts interface{}) { } } } + +func (wac *Conn) updateChats(chats interface{}) { + c, ok := chats.([]interface{}) + if !ok { + return + } + + for _, chat := range c { + chatNode, ok := chat.(binary.Node) + if !ok { + continue + } + + jid := strings.Replace(chatNode.Attributes["jid"], "@c.us", "@s.whatsapp.net", 1) + wac.Store.Chats[jid] = Chat{ + jid, + chatNode.Attributes["name"], + chatNode.Attributes["count"], + chatNode.Attributes["t"], + chatNode.Attributes["mute"], + chatNode.Attributes["spam"], + } + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 6ba94300..ef6d3a86 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -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-0.20190325075644-cc2581bbf24d +# github.com/Rhymen/go-whatsapp v0.0.2 github.com/Rhymen/go-whatsapp github.com/Rhymen/go-whatsapp/binary github.com/Rhymen/go-whatsapp/binary/proto -- cgit v1.2.3