2016-11-29 18:20:06 +00:00
|
|
|
package service
|
|
|
|
|
|
|
|
import (
|
2017-03-15 15:55:30 +00:00
|
|
|
"context"
|
2017-03-01 21:14:26 +00:00
|
|
|
"encoding/json"
|
2016-11-29 18:20:06 +00:00
|
|
|
"net/http"
|
|
|
|
|
2021-06-26 04:46:51 +00:00
|
|
|
"github.com/fleetdm/fleet/v4/server/contexts/viewer"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/websocket"
|
2021-02-03 16:47:43 +00:00
|
|
|
kitlog "github.com/go-kit/kit/log"
|
|
|
|
"github.com/igm/sockjs-go/v3/sockjs"
|
2016-11-29 18:20:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Stream Distributed Query Campaign Results and Metadata
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2021-06-07 01:10:58 +00:00
|
|
|
func makeStreamDistributedQueryCampaignResultsHandler(svc fleet.Service, logger kitlog.Logger) http.Handler {
|
2017-03-01 21:14:26 +00:00
|
|
|
opt := sockjs.DefaultOptions
|
|
|
|
opt.Websocket = true
|
2018-05-17 22:54:34 +00:00
|
|
|
opt.RawWebsocket = true
|
2021-02-10 20:13:11 +00:00
|
|
|
return sockjs.NewHandler("/api/v1/fleet/results", opt, func(session sockjs.Session) {
|
2017-03-01 21:14:26 +00:00
|
|
|
conn := &websocket.Conn{Session: session}
|
2021-02-03 16:47:43 +00:00
|
|
|
defer func() {
|
|
|
|
if p := recover(); p != nil {
|
|
|
|
logger.Log("err", p, "msg", "panic in result handler")
|
|
|
|
conn.WriteJSONError("panic in result handler")
|
|
|
|
}
|
|
|
|
session.Close(0, "none")
|
|
|
|
}()
|
2016-11-29 18:20:06 +00:00
|
|
|
|
|
|
|
// Receive the auth bearer token
|
|
|
|
token, err := conn.ReadAuthToken()
|
|
|
|
if err != nil {
|
2016-12-23 01:31:45 +00:00
|
|
|
logger.Log("err", err, "msg", "failed to read auth token")
|
2016-11-29 18:20:06 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Authenticate with the token
|
2021-06-07 01:10:58 +00:00
|
|
|
vc, err := authViewer(context.Background(), string(token), svc)
|
2016-11-29 18:20:06 +00:00
|
|
|
if err != nil || !vc.CanPerformActions() {
|
2016-12-23 01:31:45 +00:00
|
|
|
logger.Log("err", err, "msg", "unauthorized viewer")
|
2016-11-29 18:20:06 +00:00
|
|
|
conn.WriteJSONError("unauthorized")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := viewer.NewContext(context.Background(), *vc)
|
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
msg, err := conn.ReadJSONMessage()
|
|
|
|
if err != nil {
|
|
|
|
logger.Log("err", err, "msg", "reading select_campaign JSON")
|
|
|
|
conn.WriteJSONError("error reading select_campaign")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if msg.Type != "select_campaign" {
|
|
|
|
logger.Log("err", "unexpected msg type, expected select_campaign", "msg-type", msg.Type)
|
|
|
|
conn.WriteJSONError("expected select_campaign")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var info struct {
|
|
|
|
CampaignID uint `json:"campaign_id"`
|
|
|
|
}
|
|
|
|
err = json.Unmarshal(*(msg.Data.(*json.RawMessage)), &info)
|
2016-11-29 18:20:06 +00:00
|
|
|
if err != nil {
|
2017-03-01 21:14:26 +00:00
|
|
|
logger.Log("err", err, "msg", "unmarshaling select_campaign data")
|
|
|
|
conn.WriteJSONError("error unmarshaling select_campaign data")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if info.CampaignID == 0 {
|
|
|
|
logger.Log("err", "campaign ID not set")
|
|
|
|
conn.WriteJSONError("0 is not a valid campaign ID")
|
2016-11-29 18:20:06 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-03-01 21:14:26 +00:00
|
|
|
svc.StreamCampaignResults(ctx, conn, info.CampaignID)
|
|
|
|
})
|
2016-11-29 18:20:06 +00:00
|
|
|
}
|