whatsapp

package module
v0.0.0-...-10ce958 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2020 License: MIT Imports: 26 Imported by: 0

README

go-whatsapp

Package rhymen/go-whatsapp implements the WhatsApp Web API to provide a clean interface for developers. Big thanks to all contributors of the sigalor/whatsapp-web-reveng project. The official WhatsApp Business API was released in August 2018. You can check it out here.

Installation

go get gitlab.com/silas.ss/go-whatsapp

Usage

Creating a connection
import (
    whatsapp "gitlab.com/silas.ss/go-whatsapp"
)

wac, err := whatsapp.NewConn(20 * time.Second)

The duration passed to the NewConn function is used to timeout login requests. If you have a bad internet connection use a higher timeout value. This function only creates a websocket connection, it does not handle authentication.

Login
qrChan := make(chan string)
go func() {
    fmt.Printf("qr code: %v\n", <-qrChan)
    //show qr code or save it somewhere to scan
}
sess, err := wac.Login(qrChan)

The authentication process requires you to scan the qr code, that is send through the channel, with the device you are using whatsapp on. The session struct that is returned can be saved and used to restore the login without scanning the qr code again. The qr code has a ttl of 20 seconds and the login function throws a timeout err if the time has passed or any other request fails.

Restore
newSess, err := wac.RestoreWithSession(sess)

The restore function needs a valid session and returns the new session that was created.

Add message handlers
type myHandler struct{}

func (myHandler) HandleError(err error) {
	fmt.Fprintf(os.Stderr, "%v", err)
}

func (myHandler) HandleTextMessage(message whatsapp.TextMessage) {
	fmt.Println(message)
}

func (myHandler) HandleImageMessage(message whatsapp.ImageMessage) {
	fmt.Println(message)
}

func (myHandler) HandleVideoMessage(message whatsapp.VideoMessage) {
	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.

Sending text messages
text := whatsapp.TextMessage{
    Info: whatsapp.MessageInfo{
        RemoteJid: "0123456789@s.whatsapp.net",
    },
    Text: "Hello Whatsapp",
}

err := wac.Send(text)

The message will be send over the websocket. The attributes seen above are the required ones. All other relevant attributes (id, timestamp, fromMe, status) are set if they are missing in the struct. For the time being we only support text messages, but other types are planned for the near future.

This code is in no way affiliated with, authorized, maintained, sponsored or endorsed by WhatsApp or any of its affiliates or subsidiaries. This is an independent and unofficial software. Use at your own risk.

License

The MIT License (MIT)

Copyright (c) 2018

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Documentation

Overview

Package whatsapp provides a developer API to interact with the WhatsAppWeb-Servers.

Index

Constants

View Source
const (
	PresenceAvailable   = "available"
	PresenceUnavailable = "unavailable"
	PresenceComposing   = "composing"
	PresenceRecording   = "recording"
	PresencePaused      = "paused"
)
View Source
const (
	Error       MessageStatus = 0
	Pending                   = 1
	ServerAck                 = 2
	DeliveryAck               = 3
	Read                      = 4
	Played                    = 5
)

Variables

View Source
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")
)

Functions

func Download

func Download(url string, mediaKey []byte, appInfo MediaType, fileLength int) ([]byte, error)

Types

type AudioMessage

type AudioMessage struct {
	Info    MessageInfo
	Length  uint32
	Type    string
	Content io.Reader
	// contains filtered or unexported fields
}

AudioMessage represents a audio message. Unexported fields are needed for media up/downloading and media validation. Provide a io.Reader as Content for message sending.

func (*AudioMessage) Download

func (m *AudioMessage) Download() ([]byte, error)

Download is the function to retrieve media data. The media gets downloaded, validated and returned.

type AudioMessageHandler

type AudioMessageHandler interface {
	Handler
	HandleAudioMessage(message AudioMessage)
}

The AudioMessageHandler interface needs to be implemented to receive audio messages dispatched by the dispatcher.

type Chat

type Chat struct {
	Jid             string
	Name            string
	Unread          string
	LastMessageTime string
	IsMuted         string
	IsMarkedSpam    string
}

type ChatListHandler

type ChatListHandler interface {
	Handler
	HandleChatList(contacts []Chat)
}

* The ChatListHandler interface needs to be implemented to apply custom actions to chat lists dispatched by the dispatcher.

type Conn

type Conn struct {
	Info           *Info
	Store          *Store
	ServerLastSeen time.Time
	// contains filtered or unexported fields
}

Conn is created by NewConn. Interacting with the initialized Conn is the main way of interacting with our package. It holds all necessary information to make the package work internally.

func NewConn

func NewConn(timeout time.Duration) (*Conn, error)

Creates a new connection with a given timeout. The websocket connection to the WhatsAppWeb servers get´s established. The goroutine for handling incoming messages is started

func (*Conn) AddHandler

func (wac *Conn) AddHandler(handler Handler)

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 handlers(TextMessageHandler, ImageMessageHandler) are optional. At runtime it is checked if they are implemented and they are called if so and needed.

func (*Conn) AddMember

func (wac *Conn) AddMember(jid string, participants []string) (<-chan string, error)

func (*Conn) Chats

func (wac *Conn) Chats() (*binary.Node, error)

func (*Conn) Contacts

func (wac *Conn) Contacts() (*binary.Node, error)

func (*Conn) CreateGroup

func (wac *Conn) CreateGroup(subject string, participants []string) (<-chan string, error)

func (*Conn) Disconnect

func (wac *Conn) Disconnect() (Session, error)

func (*Conn) Emoji

func (wac *Conn) Emoji() (*binary.Node, error)

func (*Conn) Exist

func (wac *Conn) Exist(jid string) (<-chan string, error)

func (*Conn) GetGroupMetaData

func (wac *Conn) GetGroupMetaData(jid string) (<-chan string, error)

func (*Conn) GetProfilePicThumb

func (wac *Conn) GetProfilePicThumb(jid string) (<-chan string, error)

TODO: filename? WhatsApp uses Store.Contacts for these functions functions probably shouldn't return a string, maybe build a struct / return json check for further queries

func (*Conn) GetStatus

func (wac *Conn) GetStatus(jid string) (<-chan string, error)

func (*Conn) GroupAcceptInviteCode

func (wac *Conn) GroupAcceptInviteCode(code string) (jid string, err error)
func (wac *Conn) GroupInviteLink(jid string) (string, error)

func (*Conn) LeaveGroup

func (wac *Conn) LeaveGroup(jid string) (<-chan string, error)

func (*Conn) LoadMessages

func (wac *Conn) LoadMessages(jid, messageId string, count int) (*binary.Node, error)

func (*Conn) LoadMessagesAfter

func (wac *Conn) LoadMessagesAfter(jid, messageId string, count int) (*binary.Node, error)

func (*Conn) LoadMessagesBefore

func (wac *Conn) LoadMessagesBefore(jid, messageId string, count int) (*binary.Node, error)

func (*Conn) Login

func (wac *Conn) Login(qrChan chan<- string) (Session, 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 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:

wac, err := whatsapp.NewConn(5 * time.Second)
if err != nil {
	panic(err)
}

qr := make(chan string)
go func() {
	terminal := qrcodeTerminal.New()
	terminal.Get(<-qr).Print()
}()

session, err := wac.Login(qr)
if err != nil {
	fmt.Fprintf(os.Stderr, "error during login: %v\n", err)
}
fmt.Printf("login successful, session: %v\n", session)

func (*Conn) Logout

func (wac *Conn) Logout() error

Logout is the function to logout from a WhatsApp session. Logging out means invalidating the current session. The session can not be resumed and will disappear on your phone in the WhatsAppWeb client list.

func (*Conn) Presence

func (wac *Conn) Presence(jid string, presence Presence) (<-chan string, error)

func (*Conn) Read

func (wac *Conn) Read(jid, id string) (<-chan string, error)

func (*Conn) RemoveAdmin

func (wac *Conn) RemoveAdmin(jid string, participants []string) (<-chan string, error)

func (*Conn) RemoveHandler

func (wac *Conn) RemoveHandler(handler Handler) bool

RemoveHandler removes a handler from the list of handlers that receive dispatched messages.

func (*Conn) RemoveHandlers

func (wac *Conn) RemoveHandlers()

RemoveHandlers empties the list of handlers that receive dispatched messages.

func (*Conn) RemoveMember

func (wac *Conn) RemoveMember(jid string, participants []string) (<-chan string, error)

func (*Conn) Restore

func (wac *Conn) Restore() error

//TODO: GoDoc 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.

func (*Conn) RestoreWithSession

func (wac *Conn) RestoreWithSession(session Session) (_ Session, err error)

TODO: GoDoc

Basically the old RestoreSession functionality

func (*Conn) Search

func (wac *Conn) Search(search string, count, page int) (*binary.Node, error)

func (*Conn) Send

func (wac *Conn) Send(msg interface{}) (string, error)

func (*Conn) SetAdmin

func (wac *Conn) SetAdmin(jid string, participants []string) (<-chan string, error)

func (*Conn) SetClientName

func (wac *Conn) SetClientName(long, short, version string) error

SetClientName sets the long and short client names that are sent to WhatsApp when logging in and displayed in the WhatsApp Web device list. As the values are only sent when logging in, changing them after logging in is not possible.

func (*Conn) SubscribePresence

func (wac *Conn) SubscribePresence(jid string) (<-chan string, error)

func (*Conn) UpdateGroupSubject

func (wac *Conn) UpdateGroupSubject(subject string, jid string) (<-chan string, error)

func (*Conn) Upload

func (wac *Conn) Upload(reader io.Reader, appInfo MediaType) (downloadURL string, mediaKey []byte, fileEncSha256 []byte, fileSha256 []byte, fileLength uint64, err error)

type Contact

type Contact struct {
	Jid    string
	Notify string
	Name   string
	Short  string
}

type ContactListHandler

type ContactListHandler interface {
	Handler
	HandleContactList(contacts []Contact)
}

* The ContactListHandler interface needs to be implemented to applky custom actions to contact lists dispatched by the dispatcher.

type DocumentMessage

type DocumentMessage struct {
	Info      MessageInfo
	Title     string
	PageCount uint32
	Type      string
	FileName  string
	Thumbnail []byte
	Content   io.Reader
	// contains filtered or unexported fields
}

DocumentMessage represents a document message. Unexported fields are needed for media up/downloading and media validation. Provide a io.Reader as Content for message sending.

func (*DocumentMessage) Download

func (m *DocumentMessage) Download() ([]byte, error)

Download is the function to retrieve media data. The media gets downloaded, validated and returned.

type DocumentMessageHandler

type DocumentMessageHandler interface {
	Handler
	HandleDocumentMessage(message DocumentMessage)
}

The DocumentMessageHandler interface needs to be implemented to receive document messages dispatched by the dispatcher.

type ErrConnectionClosed

type ErrConnectionClosed struct {
	Code int
	Text string
}

func (*ErrConnectionClosed) Error

func (e *ErrConnectionClosed) Error() string

type ErrConnectionFailed

type ErrConnectionFailed struct {
	Err error
}

func (*ErrConnectionFailed) Error

func (e *ErrConnectionFailed) Error() string

type Handler

type Handler interface {
	HandleError(err error)
}

The Handler interface is the minimal interface that needs to be implemented to be accepted as a valid handler for our dispatching system. The minimal handler is used to dispatch error messages. These errors occur on unexpected behavior by the websocket connection or if we are unable to handle or interpret an incoming message. Error produced by user actions are not dispatched through this handler. They are returned as an error on the specific function call.

type IPHost

type IPHost struct {
	IPV4 string `json:"ipv4"`
	IPV6 string `json:"ipv6"`
}

type ImageMessage

type ImageMessage struct {
	Info      MessageInfo
	Caption   string
	Thumbnail []byte
	Type      string
	Content   io.Reader
	// contains filtered or unexported fields
}

ImageMessage represents a image message. Unexported fields are needed for media up/downloading and media validation. Provide a io.Reader as Content for message sending.

func (*ImageMessage) Download

func (m *ImageMessage) Download() ([]byte, error)

Download is the function to retrieve media data. The media gets downloaded, validated and returned.

type ImageMessageHandler

type ImageMessageHandler interface {
	Handler
	HandleImageMessage(message ImageMessage)
}

The ImageMessageHandler interface needs to be implemented to receive image messages dispatched by the dispatcher.

type Info

type Info struct {
	Battery   int
	Platform  string
	Connected bool
	Pushname  string
	Wid       string
	Lc        string
	Phone     *PhoneInfo
	Plugged   bool
	Tos       int
	Lg        string
	Is24h     bool
}

type JsonMessageHandler

type JsonMessageHandler interface {
	Handler
	HandleJsonMessage(message string)
}

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 to built a Store, which is used to save these "secondary" information. These messages may contain presence (available, last see) information, or just the battery status of your phone.

type MediaConn

type MediaConn struct {
	Status    int `json:"status"`
	MediaConn struct {
		Auth  string `json:"auth"`
		TTL   int    `json:"ttl"`
		Hosts []struct {
			Hostname string   `json:"hostname"`
			IPs      []IPHost `json:"ips"`
		} `json:"hosts"`
	} `json:"media_conn"`
}

type MediaType

type MediaType string
const (
	MediaImage    MediaType = "WhatsApp Image Keys"
	MediaVideo    MediaType = "WhatsApp Video Keys"
	MediaAudio    MediaType = "WhatsApp Audio Keys"
	MediaDocument MediaType = "WhatsApp Document Keys"
)

type MessageInfo

type MessageInfo struct {
	Id              string
	RemoteJid       string
	SenderJid       string
	FromMe          bool
	Timestamp       uint64
	PushName        string
	Status          MessageStatus
	QuotedMessageID string

	Source *proto.WebMessageInfo
}

MessageInfo contains general message information. It is part of every of every message type.

type MessageStatus

type MessageStatus int

type PhoneInfo

type PhoneInfo struct {
	Mcc                string
	Mnc                string
	OsVersion          string
	DeviceManufacturer string
	DeviceModel        string
	OsBuildNumber      string
	WaVersion          string
}

type Presence

type Presence string

type RawMessageHandler

type RawMessageHandler interface {
	Handler
	HandleRawMessage(message *proto.WebMessageInfo)
}

* The RawMessageHandler interface needs to be implemented to receive raw messages dispatched by the dispatcher. Raw messages are the raw protobuf structs instead of the easy-to-use structs in TextMessageHandler, ImageMessageHandler, etc..

type Session

type Session struct {
	ClientId    string
	ClientToken string
	ServerToken string
	EncKey      []byte
	MacKey      []byte
	Wid         string
}

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 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.

type Store

type Store struct {
	Contacts map[string]Contact
	Chats    map[string]Chat
}

type TextMessage

type TextMessage struct {
	Info MessageInfo
	Text string
}

TextMessage represents a text message.

type TextMessageHandler

type TextMessageHandler interface {
	Handler
	HandleTextMessage(message TextMessage)
}

The TextMessageHandler interface needs to be implemented to receive text messages dispatched by the dispatcher.

type VideoMessage

type VideoMessage struct {
	Info      MessageInfo
	Caption   string
	Thumbnail []byte
	Length    uint32
	Type      string
	Content   io.Reader
	// contains filtered or unexported fields
}

VideoMessage represents a video message. Unexported fields are needed for media up/downloading and media validation. Provide a io.Reader as Content for message sending.

func (*VideoMessage) Download

func (m *VideoMessage) Download() ([]byte, error)

Download is the function to retrieve media data. The media gets downloaded, validated and returned.

type VideoMessageHandler

type VideoMessageHandler interface {
	Handler
	HandleVideoMessage(message VideoMessage)
}

The VideoMessageHandler interface needs to be implemented to receive video messages dispatched by the dispatcher.

Directories

Path Synopsis
crypto package contains cryptographic functions and servers as a support package for gitlab.com/silas.ss/go-whatsapp.
crypto package contains cryptographic functions and servers as a support package for gitlab.com/silas.ss/go-whatsapp.
cbc
CBC describes a block cipher mode.
CBC describes a block cipher mode.
curve25519
In cryptography, Curve25519 is an elliptic curve offering 128 bits of security and designed for use with the elliptic curve Diffie–Hellman (ECDH) key agreement scheme.
In cryptography, Curve25519 is an elliptic curve offering 128 bits of security and designed for use with the elliptic curve Diffie–Hellman (ECDH) key agreement scheme.
hkdf
HKDF is a simple key derivation function (KDF) based on a hash-based message authentication code (HMAC).
HKDF is a simple key derivation function (KDF) based on a hash-based message authentication code (HMAC).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL