-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathqualys_client.go
More file actions
93 lines (82 loc) · 2.34 KB
/
Copy pathqualys_client.go
File metadata and controls
93 lines (82 loc) · 2.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package main
import (
"encoding/xml"
"fmt"
"strings"
"github.com/go-resty/resty/v2"
)
// Client wraps Resty for the QPS Tagging API
type Client struct{ r *resty.Client }
// NewClient points Resty at your QPS server
func NewQualysClient(baseURL, username, password string) *Client {
r := resty.New().
SetBaseURL(baseURL).
SetBasicAuth(username, password).
SetHeader("Content-Type", "text/xml").
SetHeader("Accept", "application/xml")
return &Client{r: r}
}
// QualysTag is one tag’s ID + name
type QualysTag struct {
ID int `xml:"id"`
Name string `xml:"name"`
}
// tagsResponse matches the <ServiceResponse><data><Tag>… XML
type tagsResponse struct {
XMLName xml.Name `xml:"ServiceResponse"`
Data struct {
Tags []QualysTag `xml:"Tag"`
} `xml:"data"`
}
func xmlEscape(s string) string {
return strings.ReplaceAll(s, "&", "&")
}
const searchTagPath = "/qps/rest/2.0/search/am/tag"
// ListTags retrieves *all* tags via a POST to the Search Tags endpoint
func (qc *Client) ListTags() ([]QualysTag, error) {
// Build a body that says “no filters, give me up to 10 000 tags”
reqBody := `
<ServiceRequest>
<preferences>
<startFromOffset>1</startFromOffset>
<limitResults>1000</limitResults>
</preferences>
</ServiceRequest>`
resp, err := qc.r.R().
SetBody(reqBody).
SetResult(&tagsResponse{}).
Post(searchTagPath)
if err != nil {
return nil, fmt.Errorf("qualys ListTags failed: %w", err)
}
if resp.StatusCode() != 200 {
return nil, fmt.Errorf("unexpected HTTP %d from Qualys:\n%s",
resp.StatusCode(), resp.String())
}
result := resp.Result().(*tagsResponse)
return result.Data.Tags, nil
}
// UpsertTag creates or updates a tag in Qualys via the QPS Update endpoint.
func (qc *Client) UpsertTag(t Tag) error {
// Build the ServiceRequest XML body.
// QPS expects <ServiceRequest><data><Tag>…</Tag></data></ServiceRequest>
reqBody := fmt.Sprintf(`
<ServiceRequest>
<data>
<Tag>
<name>%s</name>
</Tag>
</data>
</ServiceRequest>`, xmlEscape(t.Name))
resp, err := qc.r.R().
SetBody(reqBody).
Post("/qps/rest/2.0/update/am/tag")
if err != nil {
return fmt.Errorf("qualys UpsertTag request failed: %w", err)
}
if resp.StatusCode() != 200 {
return fmt.Errorf("qualys UpsertTag unexpected HTTP %d: %s",
resp.StatusCode(), resp.String())
}
return nil
}