mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-18 07:26:50 +00:00
Allow for unauthenticated/authenticated websocket command handling
This commit is contained in:
@@ -62,6 +62,7 @@ type WebserverConfig struct {
|
||||
AdminPassword string
|
||||
ListenAddress string
|
||||
WebsocketConnectionLimit int
|
||||
WebsocketMaxAuthFailures int
|
||||
WebsocketAllowInsecureOrigin bool
|
||||
}
|
||||
|
||||
@@ -346,6 +347,10 @@ func (c *Config) CheckWebserverConfigValues() error {
|
||||
c.Webserver.WebsocketConnectionLimit = 1
|
||||
}
|
||||
|
||||
if c.Webserver.WebsocketMaxAuthFailures <= 0 {
|
||||
c.Webserver.WebsocketMaxAuthFailures = 3
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
"AdminPassword": "Password",
|
||||
"ListenAddress": ":9050",
|
||||
"WebsocketConnectionLimit": 0,
|
||||
"WebsocketMaxAuthFailures": 0,
|
||||
"WebsocketAllowInsecureOrigin": false
|
||||
},
|
||||
"Exchanges": [
|
||||
|
||||
115
websocket.go
115
websocket.go
@@ -20,18 +20,22 @@ var (
|
||||
wsHubStarted bool
|
||||
)
|
||||
|
||||
type wsCommandHandler func(client *WebsocketClient, data interface{}) error
|
||||
type wsCommandHandler struct {
|
||||
authRequired bool
|
||||
handler func(client *WebsocketClient, data interface{}) error
|
||||
}
|
||||
|
||||
var wsHandlers = map[string]wsCommandHandler{
|
||||
"getconfig": wsGetConfig,
|
||||
"saveconfig": wsSaveConfig,
|
||||
"getaccountinfo": wsGetAccountInfo,
|
||||
"gettickers": wsGetTickers,
|
||||
"getticker": wsGetTicker,
|
||||
"getorderbooks": wsGetOrderbooks,
|
||||
"getorderbook": wsGetOrderbook,
|
||||
"getexchangerates": wsGetExchangeRates,
|
||||
"getportfolio": wsGetPortfolio,
|
||||
"auth": wsCommandHandler{authRequired: false, handler: wsAuth},
|
||||
"getconfig": wsCommandHandler{authRequired: true, handler: wsGetConfig},
|
||||
"saveconfig": wsCommandHandler{authRequired: true, handler: wsSaveConfig},
|
||||
"getaccountinfo": wsCommandHandler{authRequired: true, handler: wsGetAccountInfo},
|
||||
"gettickers": wsCommandHandler{authRequired: false, handler: wsGetTickers},
|
||||
"getticker": wsCommandHandler{authRequired: false, handler: wsGetTicker},
|
||||
"getorderbooks": wsCommandHandler{authRequired: false, handler: wsGetOrderbooks},
|
||||
"getorderbook": wsCommandHandler{authRequired: false, handler: wsGetOrderbook},
|
||||
"getexchangerates": wsCommandHandler{authRequired: false, handler: wsGetExchangeRates},
|
||||
"getportfolio": wsCommandHandler{authRequired: true, handler: wsGetPortfolio},
|
||||
}
|
||||
|
||||
// WebsocketClient stores information related to the websocket client
|
||||
@@ -39,6 +43,7 @@ type WebsocketClient struct {
|
||||
Hub *WebsocketHub
|
||||
Conn *websocket.Conn
|
||||
Authenticated bool
|
||||
authFailures int
|
||||
Send chan []byte
|
||||
}
|
||||
|
||||
@@ -163,50 +168,18 @@ func (c *WebsocketClient) read() {
|
||||
req := common.StringToLower(evt.Event)
|
||||
log.Printf("websocket: request received: %s", req)
|
||||
|
||||
if !c.Authenticated && evt.Event != "auth" {
|
||||
wsResp := WebsocketEventResponse{
|
||||
Event: "auth",
|
||||
Error: "you must authenticate first",
|
||||
}
|
||||
|
||||
c.SendWebsocketMessage(wsResp)
|
||||
log.Printf("websocket: client didn't auth, disconnecting!")
|
||||
break
|
||||
} else if !c.Authenticated && evt.Event == "auth" {
|
||||
var auth WebsocketAuth
|
||||
err = common.JSONDecode(dataJSON, &auth)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
hashPW := common.HexEncodeToString(common.GetSHA256([]byte(bot.config.Webserver.AdminPassword)))
|
||||
if auth.Username == bot.config.Webserver.AdminUsername && auth.Password == hashPW {
|
||||
c.Authenticated = true
|
||||
wsResp := WebsocketEventResponse{
|
||||
Event: "auth",
|
||||
Data: WebsocketResponseSuccess,
|
||||
}
|
||||
c.SendWebsocketMessage(wsResp)
|
||||
log.Println("websocket: client authenticated successfully")
|
||||
continue
|
||||
} else {
|
||||
wsResp := WebsocketEventResponse{
|
||||
Event: "auth",
|
||||
Error: "invalid username/password",
|
||||
}
|
||||
c.SendWebsocketMessage(wsResp)
|
||||
log.Printf("websocket: client sent wrong username/password")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
result, ok := wsHandlers[req]
|
||||
if !ok {
|
||||
log.Printf("websocket: unsupported event")
|
||||
continue
|
||||
}
|
||||
|
||||
err = result(c, dataJSON)
|
||||
if result.authRequired && !c.Authenticated {
|
||||
log.Printf("Websocket: request %s failed due to unauthenticated request on an authenticated API", evt.Event)
|
||||
continue
|
||||
}
|
||||
|
||||
err = result.handler(c, dataJSON)
|
||||
if err != nil {
|
||||
log.Printf("websocket: request %s failed. Error %s", evt.Event, err)
|
||||
continue
|
||||
@@ -313,6 +286,42 @@ func WebsocketClientHandler(w http.ResponseWriter, r *http.Request) {
|
||||
go client.write()
|
||||
}
|
||||
|
||||
func wsAuth(client *WebsocketClient, data interface{}) error {
|
||||
wsResp := WebsocketEventResponse{
|
||||
Event: "auth",
|
||||
}
|
||||
|
||||
var auth WebsocketAuth
|
||||
err := common.JSONDecode(data.([]byte), &auth)
|
||||
if err != nil {
|
||||
wsResp.Error = err.Error()
|
||||
client.SendWebsocketMessage(wsResp)
|
||||
return err
|
||||
}
|
||||
|
||||
hashPW := common.HexEncodeToString(common.GetSHA256([]byte(bot.config.Webserver.AdminPassword)))
|
||||
if auth.Username == bot.config.Webserver.AdminUsername && auth.Password == hashPW {
|
||||
client.Authenticated = true
|
||||
wsResp.Data = WebsocketResponseSuccess
|
||||
log.Println("websocket: client authenticated successfully")
|
||||
return client.SendWebsocketMessage(wsResp)
|
||||
} else {
|
||||
wsResp.Error = "invalid username/password"
|
||||
client.authFailures++
|
||||
client.SendWebsocketMessage(wsResp)
|
||||
if client.authFailures >= bot.config.Webserver.WebsocketMaxAuthFailures {
|
||||
log.Printf("websocket: disconnecting client, maximum auth failures threshold reached (failures: %d limit: %d)",
|
||||
client.authFailures, bot.config.Webserver.WebsocketMaxAuthFailures)
|
||||
wsHub.Unregister <- client
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("websocket: client sent wrong username/password (failures: %d limit: %d)",
|
||||
client.authFailures, bot.config.Webserver.WebsocketMaxAuthFailures)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func wsGetConfig(client *WebsocketClient, data interface{}) error {
|
||||
wsResp := WebsocketEventResponse{
|
||||
Event: "GetConfig",
|
||||
@@ -329,20 +338,14 @@ func wsSaveConfig(client *WebsocketClient, data interface{}) error {
|
||||
err := common.JSONDecode(data.([]byte), &cfg)
|
||||
if err != nil {
|
||||
wsResp.Error = err.Error()
|
||||
err = client.SendWebsocketMessage(wsResp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client.SendWebsocketMessage(wsResp)
|
||||
return err
|
||||
}
|
||||
|
||||
err = bot.config.UpdateConfig(bot.configFile, cfg)
|
||||
if err != nil {
|
||||
wsResp.Error = err.Error()
|
||||
err = client.SendWebsocketMessage(wsResp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client.SendWebsocketMessage(wsResp)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user