diff options
Diffstat (limited to 'vendor/github.com/Rhymen/go-whatsapp/write.go')
-rw-r--r-- | vendor/github.com/Rhymen/go-whatsapp/write.go | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/vendor/github.com/Rhymen/go-whatsapp/write.go b/vendor/github.com/Rhymen/go-whatsapp/write.go new file mode 100644 index 00000000..4ea63dca --- /dev/null +++ b/vendor/github.com/Rhymen/go-whatsapp/write.go @@ -0,0 +1,125 @@ +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" + "github.com/pkg/errors" + "strconv" + "time" +) + +//writeJson enqueues a json message into the writeChan +func (wac *Conn) writeJson(data []interface{}) (<-chan string, error) { + d, err := json.Marshal(data) + if err != nil { + return nil, err + } + + ts := time.Now().Unix() + messageTag := fmt.Sprintf("%d.--%d", ts, wac.msgCount) + bytes := []byte(fmt.Sprintf("%s,%s", messageTag, d)) + + ch, err := wac.write(websocket.TextMessage, messageTag, bytes) + if err != nil { + return nil, err + } + + wac.msgCount++ + return ch, nil +} + +func (wac *Conn) writeBinary(node binary.Node, metric metric, flag flag, messageTag string) (<-chan string, error) { + if len(messageTag) < 2 { + return nil, ErrMissingMessageTag + } + + data, err := wac.encryptBinaryMessage(node) + if err != nil { + return nil, errors.Wrap(err, "encryptBinaryMessage(node) failed") + } + + bytes := []byte(messageTag + ",") + bytes = append(bytes, byte(metric), byte(flag)) + bytes = append(bytes, data...) + + ch, err := wac.write(websocket.BinaryMessage, messageTag, bytes) + if err != nil { + return nil, errors.Wrap(err, "failed to write message") + } + + wac.msgCount++ + return ch, nil +} + +func (wac *Conn) sendKeepAlive() error { + bytes := []byte("?,,") + respChan, err := wac.write(websocket.TextMessage, "!", bytes) + if err != nil { + return errors.Wrap(err, "error sending keepAlive") + } + + select { + case resp := <-respChan: + msecs, err := strconv.ParseInt(resp, 10, 64) + if err != nil { + return errors.Wrap(err, "Error converting time string to uint") + } + wac.ServerLastSeen = time.Unix(msecs/1000, (msecs%1000)*int64(time.Millisecond)) + + case <-time.After(wac.msgTimeout): + return ErrConnectionTimeout + } + + return nil +} + +func (wac *Conn) write(messageType int, answerMessageTag string, data []byte) (<-chan string, error) { + var ch chan string + if answerMessageTag != "" { + ch = make(chan string, 1) + + wac.listener.Lock() + wac.listener.m[answerMessageTag] = ch + wac.listener.Unlock() + } + + wac.ws.Lock() + err := wac.ws.conn.WriteMessage(messageType, data) + wac.ws.Unlock() + + if err != nil { + if answerMessageTag != "" { + wac.listener.Lock() + delete(wac.listener.m, answerMessageTag) + wac.listener.Unlock() + } + return nil, errors.Wrap(err, "error writing to websocket") + } + return ch, nil +} + +func (wac *Conn) encryptBinaryMessage(node binary.Node) (data []byte, err error) { + b, err := binary.Marshal(node) + if err != nil { + return nil, errors.Wrap(err, "binary node marshal failed") + } + + cipher, err := cbc.Encrypt(wac.session.EncKey, nil, b) + if err != nil { + return nil, errors.Wrap(err, "encrypt failed") + } + + h := hmac.New(sha256.New, wac.session.MacKey) + h.Write(cipher) + hash := h.Sum(nil) + + data = append(data, hash[:32]...) + data = append(data, cipher...) + + return data, nil +} |