94 lines
2.1 KiB
Go
94 lines
2.1 KiB
Go
|
package obsws
|
||
|
|
||
|
import (
|
||
|
"crypto/sha256"
|
||
|
"encoding/base64"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
|
||
|
"github.com/gorilla/websocket"
|
||
|
)
|
||
|
|
||
|
// Connect opens a WebSocket connection and authenticates if necessary.
|
||
|
func (c *Client) Connect() error {
|
||
|
c.handlers = make(map[string]func(Event))
|
||
|
c.respQ = make(chan map[string]interface{}, bufferSize)
|
||
|
|
||
|
conn, err := connectWS(c.Host, c.Port)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
c.conn = conn
|
||
|
|
||
|
// We can't use SendReceive yet because we haven't started polling.
|
||
|
|
||
|
reqGAR := NewGetAuthRequiredRequest()
|
||
|
if err = c.conn.WriteJSON(reqGAR); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
respGAR := &GetAuthRequiredResponse{}
|
||
|
if err = c.conn.ReadJSON(respGAR); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if !respGAR.AuthRequired {
|
||
|
Logger.Println("logged in (no authentication required)")
|
||
|
c.connected = true
|
||
|
go c.poll()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
auth := getAuth(c.Password, respGAR.Salt, respGAR.Challenge)
|
||
|
Logger.Println("auth:", auth)
|
||
|
|
||
|
reqA := NewAuthenticateRequest(auth)
|
||
|
if err = c.conn.WriteJSON(reqA); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
respA := &AuthenticateResponse{}
|
||
|
if err = c.conn.ReadJSON(respA); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if respA.Status() != "ok" {
|
||
|
return errors.New(respA.Error())
|
||
|
}
|
||
|
|
||
|
Logger.Println("logged in (authentication successful)")
|
||
|
c.connected = true
|
||
|
go c.poll()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Disconnect closes the WebSocket connection.
|
||
|
func (c *Client) Disconnect() error {
|
||
|
c.connected = false
|
||
|
if err := c.conn.Close(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// connectWS opens the WebSocket connection.
|
||
|
func connectWS(host string, port int) (*websocket.Conn, error) {
|
||
|
url := fmt.Sprintf("ws://%s:%d", host, port)
|
||
|
Logger.Println("connecting to", url)
|
||
|
conn, _, err := websocket.DefaultDialer.Dial(url, nil)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return conn, nil
|
||
|
}
|
||
|
|
||
|
// getAuth computes the auth challenge response.
|
||
|
func getAuth(password, salt, challenge string) string {
|
||
|
sha := sha256.Sum256([]byte(password + salt))
|
||
|
b64 := base64.StdEncoding.EncodeToString([]byte(sha[:]))
|
||
|
|
||
|
sha = sha256.Sum256([]byte(b64 + challenge))
|
||
|
b64 = base64.StdEncoding.EncodeToString([]byte(sha[:]))
|
||
|
|
||
|
return b64
|
||
|
}
|