diff --git a/service/whatsapp/README.md b/service/whatsapp/README.md index d261714..2a05d38 100644 --- a/service/whatsapp/README.md +++ b/service/whatsapp/README.md @@ -8,7 +8,17 @@ You will need a registered WhatsApp phone number to be used as source for sendin ## Usage -In the current implementation, authentication requires scanning QR code from terminal using a registered WhatsApp device. Please refer [Login (go-whatsapp)](https://github.com/Rhymen/go-whatsapp#login) and [sigalor/whatsapp-web-reveng](https://github.com/sigalor/whatsapp-web-reveng) for more details. +In the current implementation, authentication is implemented using 2 ways: + +1. Scanning QR code from terminal using a registered WhatsApp device. + + - Go to WhatsApp on your device. + - Click on the ellipsis icon (3 vertical dots) on top right, then click on "WhatsApp Web". + - Click on the "+" icon and scan the QR code from terminal. + +> Refer: [Login (go-whatsapp)](https://github.com/Rhymen/go-whatsapp#login) and [sigalor/whatsapp-web-reveng](https://github.com/sigalor/whatsapp-web-reveng) for more details. + +2. Providing the Session credentials explicitly. ```go package main @@ -26,6 +36,11 @@ func main() { log.Fatalf("whatsapp.New() failed: %s", err.Error()) } + err = whatsappSvc.LoginWithQRCode() + if err != nil { + log.Fatalf("whatsappSvc.LoginWithQRCode() failed: %s", err.Error()) + } + whatsappSvc.AddReceivers("Contact1") notifier := notify.New() diff --git a/service/whatsapp/doc.go b/service/whatsapp/doc.go index c378abf..6ea71e7 100644 --- a/service/whatsapp/doc.go +++ b/service/whatsapp/doc.go @@ -18,6 +18,11 @@ Usage: log.Fatalf("whatsapp.New() failed: %s", err.Error()) } + err = whatsappSvc.LoginWithQRCode() + if err != nil { + log.Fatalf("whatsappSvc.LoginWithQRCode() failed: %s", err.Error()) + } + whatsappSvc.AddReceivers("Contact1") notifier := notify.New() diff --git a/service/whatsapp/mock_whatsappClient.go b/service/whatsapp/mock_whatsappClient.go index a8bd5bb..2eaec39 100644 --- a/service/whatsapp/mock_whatsappClient.go +++ b/service/whatsapp/mock_whatsappClient.go @@ -2,13 +2,58 @@ package whatsapp -import mock "github.com/stretchr/testify/mock" +import ( + "github.com/Rhymen/go-whatsapp" + "github.com/stretchr/testify/mock" +) // mockWhatsappClient is an autogenerated mock type for the whatsappClient type type mockWhatsappClient struct { mock.Mock } +// Login provides a mock function with given fields: qrChan +func (_m *mockWhatsappClient) Login(qrChan chan<- string) (whatsapp.Session, error) { + ret := _m.Called(qrChan) + + var r0 whatsapp.Session + if rf, ok := ret.Get(0).(func(chan<- string) whatsapp.Session); ok { + r0 = rf(qrChan) + } else { + r0 = ret.Get(0).(whatsapp.Session) + } + + var r1 error + if rf, ok := ret.Get(1).(func(chan<- string) error); ok { + r1 = rf(qrChan) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RestoreWithSession provides a mock function with given fields: session +func (_m *mockWhatsappClient) RestoreWithSession(session whatsapp.Session) (whatsapp.Session, error) { + ret := _m.Called(session) + + var r0 whatsapp.Session + if rf, ok := ret.Get(0).(func(whatsapp.Session) whatsapp.Session); ok { + r0 = rf(session) + } else { + r0 = ret.Get(0).(whatsapp.Session) + } + + var r1 error + if rf, ok := ret.Get(1).(func(whatsapp.Session) error); ok { + r1 = rf(session) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Send provides a mock function with given fields: msg func (_m *mockWhatsappClient) Send(msg interface{}) (string, error) { ret := _m.Called(msg) diff --git a/service/whatsapp/whatsapp.go b/service/whatsapp/whatsapp.go index d9b18ae..0606080 100644 --- a/service/whatsapp/whatsapp.go +++ b/service/whatsapp/whatsapp.go @@ -7,17 +7,19 @@ import ( "time" qrcodeTerminal "github.com/Baozisoftware/qrcode-terminal-go" - whatsapp "github.com/Rhymen/go-whatsapp" + "github.com/Rhymen/go-whatsapp" "github.com/pkg/errors" ) const ( - loginWaitTimeSeconds = 3 - clientTimeout = 5 + qrLoginWaitTimeSeconds = 3 + clientTimeout = 5 ) // whatsappClient abstracts go-whatsapp for writing unit tests type whatsappClient interface { + Login(qrChan chan<- string) (whatsapp.Session, error) + RestoreWithSession(session whatsapp.Session) (whatsapp.Session, error) Send(msg interface{}) (string, error) } @@ -34,13 +36,6 @@ func New() (*Service, error) { return nil, err } - err = login(client) - if err != nil { - return nil, err - } - - <-time.After(loginWaitTimeSeconds * time.Second) - s := &Service{ client: client, contacts: []string{}, @@ -48,12 +43,37 @@ func New() (*Service, error) { return s, nil } -// login helps with the WhatsApp authentication process. +// LoginWithSessionCredentials provides helper for authentication using whatsapp.Session credentials. +func (s *Service) LoginWithSessionCredentials(clientID, clientToken, serverToken, wid string, encKey, macKey []byte) error { + session := whatsapp.Session{ + ClientId: clientID, + ClientToken: clientToken, + ServerToken: serverToken, + Wid: wid, + EncKey: encKey, + MacKey: macKey, + } + + session, err := s.client.RestoreWithSession(session) + if err != nil { + return fmt.Errorf("restoring session failed: %v", err) + } + + // Save the updated session for future use without login. + err = writeSession(&session) + if err != nil { + return fmt.Errorf("error saving session: %v", err) + } + + return nil +} + +// LoginWithQRCode provides helper for authentication using QR code on terminal. // Refer: https://github.com/Rhymen/go-whatsapp#login for more information. -func login(client *whatsapp.Conn) error { +func (s *Service) LoginWithQRCode() error { session, err := readSession() if err == nil { - session, err = client.RestoreWithSession(session) + session, err = s.client.RestoreWithSession(session) if err != nil { return fmt.Errorf("restoring session failed: %v", err) } @@ -65,7 +85,7 @@ func login(client *whatsapp.Conn) error { terminal.Get(<-qr).Print() }() - session, err = client.Login(qr) + session, err = s.client.Login(qr) if err != nil { return fmt.Errorf("error during login: %v", err) } @@ -76,6 +96,8 @@ func login(client *whatsapp.Conn) error { return fmt.Errorf("error saving session: %v", err) } + <-time.After(qrLoginWaitTimeSeconds * time.Second) + return nil } diff --git a/service/whatsapp/whatsapp_test.go b/service/whatsapp/whatsapp_test.go index 6d02f66..f30c1c4 100644 --- a/service/whatsapp/whatsapp_test.go +++ b/service/whatsapp/whatsapp_test.go @@ -3,7 +3,7 @@ package whatsapp import ( "testing" - whatsapp "github.com/Rhymen/go-whatsapp" + "github.com/Rhymen/go-whatsapp" "github.com/pkg/errors" "github.com/stretchr/testify/require" )