Skip to content

Commit 5f3d72b

Browse files
authored
Merge pull request #658 from jmpsec/cli-lookup-identifier
Adding support to `osctrl-cli` to look up nodes via `osctrl-api`
2 parents 42c0be1 + 0b5af7a commit 5f3d72b

File tree

13 files changed

+140
-106
lines changed

13 files changed

+140
-106
lines changed

cmd/api/handlers/nodes.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ func (h *HandlersApi) LookupNodeHandler(w http.ResponseWriter, r *http.Request)
247247
} else {
248248
apiErrorResponse(w, "error getting node", http.StatusInternalServerError, err)
249249
}
250+
return
250251
}
251252
// Serialize and serve JSON
252-
utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, _nodeToApiLookupResponse(n))
253+
utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, n)
253254
}

cmd/api/handlers/utils.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"net/http"
55

66
"github.com/jmpsec/osctrl/pkg/logging"
7-
"github.com/jmpsec/osctrl/pkg/nodes"
87
"github.com/jmpsec/osctrl/pkg/types"
98
"github.com/jmpsec/osctrl/pkg/utils"
109
"github.com/rs/zerolog/log"
@@ -54,20 +53,3 @@ func checkValidPlatform(platforms []string, platform string) bool {
5453
}
5554
return false
5655
}
57-
58-
// Helper to convert a node into a ApiLookupResponse
59-
func _nodeToApiLookupResponse(node nodes.OsqueryNode) types.ApiLookupResponse {
60-
return types.ApiLookupResponse{
61-
UUID: node.UUID,
62-
Platform: node.Platform,
63-
PlatformVersion: node.PlatformVersion,
64-
OsqueryVersion: node.OsqueryVersion,
65-
Hostname: node.Hostname,
66-
Localname: node.Localname,
67-
IPAddress: node.IPAddress,
68-
Username: node.Username,
69-
Environment: node.Environment,
70-
HardwareSerial: node.HardwareSerial,
71-
LastSeen: node.LastSeen.String(),
72-
}
73-
}

cmd/cli/api-carve.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package main
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"fmt"
6-
"strings"
7+
"path"
78

89
"github.com/jmpsec/osctrl/pkg/carves"
910
"github.com/jmpsec/osctrl/pkg/queries"
@@ -15,7 +16,7 @@ import (
1516
// GetCarveQueries to retrieve carves from osctrl
1617
func (api *OsctrlAPI) GetCarveQueries(target, env string) ([]queries.DistributedQuery, error) {
1718
var qs []queries.DistributedQuery
18-
reqURL := fmt.Sprintf("%s%s%s/%s/queries/%s", api.Configuration.URL, APIPath, APICarves, env, target)
19+
reqURL := path.Join(api.Configuration.URL, APIPath, APICarves, env, "queries", target)
1920
rawCs, err := api.GetGeneric(reqURL, nil)
2021
if err != nil {
2122
return qs, fmt.Errorf("error api request - %w - %s", err, string(rawCs))
@@ -29,7 +30,7 @@ func (api *OsctrlAPI) GetCarveQueries(target, env string) ([]queries.Distributed
2930
// GetCarves to retrieve carves from osctrl
3031
func (api *OsctrlAPI) GetCarves(env string) ([]carves.CarvedFile, error) {
3132
var cs []carves.CarvedFile
32-
reqURL := fmt.Sprintf("%s%s%s/%s/list", api.Configuration.URL, APIPath, APICarves, env)
33+
reqURL := path.Join(api.Configuration.URL, APIPath, APICarves, env, "list")
3334
rawCs, err := api.GetGeneric(reqURL, nil)
3435
if err != nil {
3536
return cs, fmt.Errorf("error api request - %w - %s", err, string(rawCs))
@@ -43,7 +44,7 @@ func (api *OsctrlAPI) GetCarves(env string) ([]carves.CarvedFile, error) {
4344
// GetCarve to retrieve one carve from osctrl
4445
func (api *OsctrlAPI) GetCarve(env, name string) (carves.CarvedFile, error) {
4546
var c carves.CarvedFile
46-
reqURL := fmt.Sprintf("%s%s%s/%s/%s", api.Configuration.URL, APIPath, APICarves, env, name)
47+
reqURL := path.Join(api.Configuration.URL, APIPath, APICarves, env, name)
4748
rawC, err := api.GetGeneric(reqURL, nil)
4849
if err != nil {
4950
return c, fmt.Errorf("error api request - %w - %s", err, string(rawC))
@@ -57,7 +58,7 @@ func (api *OsctrlAPI) GetCarve(env, name string) (carves.CarvedFile, error) {
5758
// DeleteCarve to delete carve from osctrl
5859
func (api *OsctrlAPI) DeleteCarve(env, name string) (types.ApiGenericResponse, error) {
5960
var r types.ApiGenericResponse
60-
reqURL := fmt.Sprintf("%s%s%s/%s/%s/%s", api.Configuration.URL, APIPath, APICarves, env, settings.CarveDelete, name)
61+
reqURL := path.Join(api.Configuration.URL, APIPath, APICarves, env, settings.CarveDelete, name)
6162
rawQ, err := api.PostGeneric(reqURL, nil)
6263
if err != nil {
6364
return r, fmt.Errorf("error api request - %w - %s", err, string(rawQ))
@@ -71,7 +72,7 @@ func (api *OsctrlAPI) DeleteCarve(env, name string) (types.ApiGenericResponse, e
7172
// ExpireCarve to expire carve from osctrl
7273
func (api *OsctrlAPI) ExpireCarve(env, name string) (types.ApiGenericResponse, error) {
7374
var r types.ApiGenericResponse
74-
reqURL := fmt.Sprintf("%s%s%s/%s/%s/%s", api.Configuration.URL, APIPath, APICarves, env, settings.QueryExpire, name)
75+
reqURL := path.Join(api.Configuration.URL, APIPath, APICarves, env, settings.QueryExpire, name)
7576
rawQ, err := api.PostGeneric(reqURL, nil)
7677
if err != nil {
7778
return r, fmt.Errorf("error api request - %w - %s", err, string(rawQ))
@@ -85,7 +86,7 @@ func (api *OsctrlAPI) ExpireCarve(env, name string) (types.ApiGenericResponse, e
8586
// CompleteCarve to complete a carve from osctrl
8687
func (api *OsctrlAPI) CompleteCarve(env, name string) (types.ApiGenericResponse, error) {
8788
var r types.ApiGenericResponse
88-
reqURL := fmt.Sprintf("%s%s%s/%s/%s/%s", api.Configuration.URL, APIPath, APICarves, env, settings.CarveComplete, name)
89+
reqURL := path.Join(api.Configuration.URL, APIPath, APICarves, env, settings.CarveComplete, name)
8990
rawQ, err := api.PostGeneric(reqURL, nil)
9091
if err != nil {
9192
return r, fmt.Errorf("error api request - %w - %s", err, string(rawQ))
@@ -97,19 +98,19 @@ func (api *OsctrlAPI) CompleteCarve(env, name string) (types.ApiGenericResponse,
9798
}
9899

99100
// RunCarve to initiate a carve in osctrl
100-
func (api *OsctrlAPI) RunCarve(env, uuid, path string, exp int) (types.ApiQueriesResponse, error) {
101+
func (api *OsctrlAPI) RunCarve(env, uuid, fPath string, exp int) (types.ApiQueriesResponse, error) {
101102
c := types.ApiDistributedCarveRequest{
102103
UUID: uuid,
103-
Path: path,
104+
Path: fPath,
104105
ExpHours: exp,
105106
}
106107
var r types.ApiQueriesResponse
107-
reqURL := fmt.Sprintf("%s%s%s/%s", api.Configuration.URL, APIPath, APICarves, env)
108+
reqURL := path.Join(api.Configuration.URL, APIPath, APICarves, env)
108109
jsonMessage, err := json.Marshal(c)
109110
if err != nil {
110111
log.Err(err).Msg("error marshaling data")
111112
}
112-
jsonParam := strings.NewReader(string(jsonMessage))
113+
jsonParam := bytes.NewReader(jsonMessage)
113114
rawC, err := api.PostGeneric(reqURL, jsonParam)
114115
if err != nil {
115116
return r, fmt.Errorf("error api request - %w - %s", err, string(rawC))

cmd/cli/api-environment.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66
"io"
7+
"path"
78

89
"github.com/jmpsec/osctrl/pkg/environments"
910
"github.com/jmpsec/osctrl/pkg/settings"
@@ -13,7 +14,7 @@ import (
1314
// GetEnvironments to retrieve all environments from osctrl
1415
func (api *OsctrlAPI) GetEnvironments() ([]environments.TLSEnvironment, error) {
1516
var envs []environments.TLSEnvironment
16-
reqURL := fmt.Sprintf("%s%s%s", api.Configuration.URL, APIPath, APIEnvironments)
17+
reqURL := path.Join("%s%s%s", api.Configuration.URL, APIPath, APIEnvironments)
1718
rawEnvs, err := api.GetGeneric(reqURL, nil)
1819
if err != nil {
1920
return envs, fmt.Errorf("error api request - %w - %s", err, string(rawEnvs))
@@ -27,7 +28,7 @@ func (api *OsctrlAPI) GetEnvironments() ([]environments.TLSEnvironment, error) {
2728
// GetEnvironment to retrieve users from osctrl
2829
func (api *OsctrlAPI) GetEnvironment(identifier string) (environments.TLSEnvironment, error) {
2930
var e environments.TLSEnvironment
30-
reqURL := fmt.Sprintf("%s%s%s/%s", api.Configuration.URL, APIPath, APIEnvironments, identifier)
31+
reqURL := path.Join("%s%s%s/%s", api.Configuration.URL, APIPath, APIEnvironments, identifier)
3132
rawE, err := api.GetGeneric(reqURL, nil)
3233
if err != nil {
3334
return e, fmt.Errorf("error api request - %w - %s", err, string(rawE))
@@ -41,7 +42,7 @@ func (api *OsctrlAPI) GetEnvironment(identifier string) (environments.TLSEnviron
4142
// GetEnvMap to retrieve a map of environments by ID
4243
func (api *OsctrlAPI) GetEnvMap() (environments.MapEnvByID, error) {
4344
var envMap environments.MapEnvByID
44-
reqURL := fmt.Sprintf("%s%s%s/map/id", api.Configuration.URL, APIPath, APIEnvironments)
45+
reqURL := path.Join(api.Configuration.URL, APIPath, APIEnvironments, "map", "id")
4546
rawE, err := api.GetGeneric(reqURL, nil)
4647
if err != nil {
4748
return envMap, fmt.Errorf("error api request - %w - %s", err, string(rawE))
@@ -95,7 +96,7 @@ func (api *OsctrlAPI) NotexpireRemove(identifier string) (string, error) {
9596
// ExtendEnrollment to extend in time the enrollment URL of an environment
9697
func (api *OsctrlAPI) ActionEnrollmentRemove(identifier, action, target string, data io.Reader) (string, error) {
9798
var res types.ApiGenericResponse
98-
reqURL := fmt.Sprintf("%s%s%s/%s/%s/%s", api.Configuration.URL, APIPath, APIEnvironments, identifier, target, action)
99+
reqURL := path.Join(api.Configuration.URL, APIPath, APIEnvironments, identifier, target, action)
99100
rawE, err := api.PostGeneric(reqURL, data)
100101
if err != nil {
101102
return "", fmt.Errorf("error api request - %w - %s", err, string(rawE))

cmd/cli/api-login.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package main
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"fmt"
6-
"strings"
7+
"path"
78

89
"github.com/jmpsec/osctrl/pkg/types"
910
)
@@ -20,8 +21,8 @@ func (api *OsctrlAPI) PostLogin(env, username, password string, expHours int) (t
2021
if err != nil {
2122
return res, fmt.Errorf("error marshaling data %w", err)
2223
}
23-
jsonParam := strings.NewReader(string(jsonMessage))
24-
reqURL := fmt.Sprintf("%s%s%s/%s", api.Configuration.URL, APIPath, APILogin, env)
24+
jsonParam := bytes.NewReader(jsonMessage)
25+
reqURL := path.Join(api.Configuration.URL, APIPath, APILogin, env)
2526
rawRes, err := api.PostGeneric(reqURL, jsonParam)
2627
if err != nil {
2728
return res, fmt.Errorf("error api request - %w - %s", err, string(rawRes))

cmd/cli/api-node.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package main
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"fmt"
6-
"strings"
7+
"path"
78

89
"github.com/jmpsec/osctrl/pkg/nodes"
910
"github.com/jmpsec/osctrl/pkg/types"
@@ -12,7 +13,7 @@ import (
1213
// GetNodes to retrieve nodes from osctrl
1314
func (api *OsctrlAPI) GetNodes(env, target string) ([]nodes.OsqueryNode, error) {
1415
var nds []nodes.OsqueryNode
15-
reqURL := fmt.Sprintf("%s%s%s/%s/%s", api.Configuration.URL, APIPath, APINodes, env, target)
16+
reqURL := path.Join(api.Configuration.URL, APIPath, APINodes, env, target)
1617
rawNodes, err := api.GetGeneric(reqURL, nil)
1718
if err != nil {
1819
return nds, fmt.Errorf("error api request - %w - %s", err, string(rawNodes))
@@ -26,7 +27,7 @@ func (api *OsctrlAPI) GetNodes(env, target string) ([]nodes.OsqueryNode, error)
2627
// GetNode to retrieve one node from osctrl
2728
func (api *OsctrlAPI) GetNode(env, identifier string) (nodes.OsqueryNode, error) {
2829
var node nodes.OsqueryNode
29-
reqURL := fmt.Sprintf("%s%s%s/%s/node/%s", api.Configuration.URL, APIPath, APINodes, env, identifier)
30+
reqURL := path.Join(api.Configuration.URL, APIPath, APINodes, env, "node", identifier)
3031
rawNode, err := api.GetGeneric(reqURL, nil)
3132
if err != nil {
3233
return node, fmt.Errorf("error api request - %w - %s", err, string(rawNode))
@@ -43,12 +44,12 @@ func (api *OsctrlAPI) DeleteNode(env, identifier string) error {
4344
UUID: identifier,
4445
}
4546
var r types.ApiGenericResponse
46-
reqURL := fmt.Sprintf("%s%s%s/%s/delete", api.Configuration.URL, APIPath, APINodes, env)
47+
reqURL := path.Join(api.Configuration.URL, APIPath, APINodes, env, "delete")
4748
jsonMessage, err := json.Marshal(n)
4849
if err != nil {
4950
return fmt.Errorf("error marshaling data - %w", err)
5051
}
51-
jsonParam := strings.NewReader(string(jsonMessage))
52+
jsonParam := bytes.NewReader(jsonMessage)
5253
rawN, err := api.PostGeneric(reqURL, jsonParam)
5354
if err != nil {
5455
return fmt.Errorf("error api request - %w - %s", err, string(rawN))
@@ -63,3 +64,25 @@ func (api *OsctrlAPI) DeleteNode(env, identifier string) error {
6364
func (api *OsctrlAPI) TagNode(env, identifier, tag string) error {
6465
return nil
6566
}
67+
68+
// LookupNode to look up node from osctrl by identifier (UUID, localname or hostname)
69+
func (api *OsctrlAPI) LookupNode(identifier string) (nodes.OsqueryNode, error) {
70+
var node nodes.OsqueryNode
71+
l := types.ApiLookupRequest{
72+
Identifier: identifier,
73+
}
74+
jsonMessage, err := json.Marshal(l)
75+
if err != nil {
76+
return node, fmt.Errorf("error marshaling data %w", err)
77+
}
78+
jsonParam := bytes.NewReader(jsonMessage)
79+
reqURL := path.Join(api.Configuration.URL, APIPath, APINodes, "lookup")
80+
rawNode, err := api.PostGeneric(reqURL, jsonParam)
81+
if err != nil {
82+
return node, fmt.Errorf("error api request - %w - %s", err, string(rawNode))
83+
}
84+
if err := json.Unmarshal(rawNode, &node); err != nil {
85+
return node, fmt.Errorf("can not parse body - %w", err)
86+
}
87+
return node, nil
88+
}

cmd/cli/api-query.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package main
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"fmt"
6-
"strings"
7+
"path"
78

89
"github.com/jmpsec/osctrl/pkg/queries"
910
"github.com/jmpsec/osctrl/pkg/settings"
@@ -13,7 +14,7 @@ import (
1314
// GetQueries to retrieve queries from osctrl
1415
func (api *OsctrlAPI) GetQueries(target, env string) ([]queries.DistributedQuery, error) {
1516
var qs []queries.DistributedQuery
16-
reqURL := fmt.Sprintf("%s%s%s/%s/list/%s", api.Configuration.URL, APIPath, APIQueries, env, target)
17+
reqURL := path.Join(api.Configuration.URL, APIPath, APIQueries, env, "list", target)
1718
rawQs, err := api.GetGeneric(reqURL, nil)
1819
if err != nil {
1920
return qs, fmt.Errorf("error api request - %w - %s", err, string(rawQs))
@@ -27,7 +28,7 @@ func (api *OsctrlAPI) GetQueries(target, env string) ([]queries.DistributedQuery
2728
// GetQuery to retrieve one query from osctrl
2829
func (api *OsctrlAPI) GetQuery(env, name string) (queries.DistributedQuery, error) {
2930
var q queries.DistributedQuery
30-
reqURL := fmt.Sprintf("%s%s%s/%s/%s", api.Configuration.URL, APIPath, APIQueries, env, name)
31+
reqURL := path.Join(api.Configuration.URL, APIPath, APIQueries, env, name)
3132
rawQ, err := api.GetGeneric(reqURL, nil)
3233
if err != nil {
3334
return q, fmt.Errorf("error api request - %w - %s", err, string(rawQ))
@@ -41,7 +42,7 @@ func (api *OsctrlAPI) GetQuery(env, name string) (queries.DistributedQuery, erro
4142
// DeleteQuery to delete query from osctrl
4243
func (api *OsctrlAPI) DeleteQuery(env, name string) (types.ApiGenericResponse, error) {
4344
var r types.ApiGenericResponse
44-
reqURL := fmt.Sprintf("%s%s%s/%s/%s/%s", api.Configuration.URL, APIPath, APIQueries, env, settings.QueryDelete, name)
45+
reqURL := path.Join(api.Configuration.URL, APIPath, APIQueries, env, settings.QueryDelete, name)
4546
rawQ, err := api.PostGeneric(reqURL, nil)
4647
if err != nil {
4748
return r, fmt.Errorf("error api request - %w - %s", err, string(rawQ))
@@ -55,7 +56,7 @@ func (api *OsctrlAPI) DeleteQuery(env, name string) (types.ApiGenericResponse, e
5556
// ExpireQuery to expire query from osctrl
5657
func (api *OsctrlAPI) ExpireQuery(env, name string) (types.ApiGenericResponse, error) {
5758
var r types.ApiGenericResponse
58-
reqURL := fmt.Sprintf("%s%s%s/%s/%s/%s", api.Configuration.URL, APIPath, APIQueries, env, settings.QueryExpire, name)
59+
reqURL := path.Join(api.Configuration.URL, APIPath, APIQueries, env, settings.QueryExpire, name)
5960
rawQ, err := api.PostGeneric(reqURL, nil)
6061
if err != nil {
6162
return r, fmt.Errorf("error api request - %w - %s", err, string(rawQ))
@@ -69,7 +70,7 @@ func (api *OsctrlAPI) ExpireQuery(env, name string) (types.ApiGenericResponse, e
6970
// CompleteQuery to complete a query from osctrl
7071
func (api *OsctrlAPI) CompleteQuery(env, name string) (types.ApiGenericResponse, error) {
7172
var r types.ApiGenericResponse
72-
reqURL := fmt.Sprintf("%s%s%s/%s/%s/%s", api.Configuration.URL, APIPath, APIQueries, env, settings.QueryComplete, name)
73+
reqURL := path.Join(api.Configuration.URL, APIPath, APIQueries, env, settings.QueryComplete, name)
7374
rawQ, err := api.PostGeneric(reqURL, nil)
7475
if err != nil {
7576
return r, fmt.Errorf("error api request - %w - %s", err, string(rawQ))
@@ -89,13 +90,13 @@ func (api *OsctrlAPI) RunQuery(env, uuid, query string, hidden bool, exp int) (t
8990
ExpHours: exp,
9091
}
9192
var r types.ApiQueriesResponse
92-
reqURL := fmt.Sprintf("%s%s%s/%s", api.Configuration.URL, APIPath, APIQueries, env)
93+
reqURL := path.Join(api.Configuration.URL, APIPath, APIQueries, env)
9394
jsonMessage, err := json.Marshal(q)
9495
if err != nil {
9596
return r, fmt.Errorf("error marshaling data - %w", err)
9697

9798
}
98-
jsonParam := strings.NewReader(string(jsonMessage))
99+
jsonParam := bytes.NewReader(jsonMessage)
99100
rawQ, err := api.PostGeneric(reqURL, jsonParam)
100101
if err != nil {
101102
return r, fmt.Errorf("error api request - %w - %s", err, string(rawQ))

0 commit comments

Comments
 (0)