forked from projectdiscovery/uncover
-
Notifications
You must be signed in to change notification settings - Fork 0
/
quake.go
124 lines (103 loc) · 3.06 KB
/
quake.go
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package quake
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"github.com/010blue/uncover/sources"
errorutil "github.com/projectdiscovery/utils/errors"
)
const (
URL = "https://quake.360.net/api/v3/search/quake_service"
Size = 100
)
type Agent struct{}
func (agent *Agent) Name() string {
return "quake"
}
func (agent *Agent) Query(session *sources.Session, query *sources.Query) (chan sources.Result, error) {
if session.Keys.QuakeToken == "" {
return nil, errors.New("empty quake keys")
}
results := make(chan sources.Result)
go func() {
defer close(results)
numberOfResults := 0
for {
quakeRequest := &Request{
Query: query.Query,
Size: Size,
Start: numberOfResults,
IgnoreCache: true,
Include: []string{"ip", "port", "hostname"},
}
quakeResponse := agent.query(URL, session, quakeRequest, results)
if quakeResponse == nil {
break
}
if numberOfResults > query.Limit || len(quakeResponse.Data) == 0 {
break
}
numberOfResults += len(quakeResponse.Data)
// early exit without more results
if quakeResponse.Meta.Pagination.Count > 0 && numberOfResults >= quakeResponse.Meta.Pagination.Total {
break
}
}
}()
return results, nil
}
func (agent *Agent) query(URL string, session *sources.Session, quakeRequest *Request, results chan sources.Result) *Response {
resp, err := agent.queryURL(session, URL, quakeRequest)
if err != nil {
results <- sources.Result{Source: agent.Name(), Error: err}
return nil
}
quakeResponse := &Response{}
respdata, err := io.ReadAll(resp.Body)
if err != nil {
results <- sources.Result{Source: agent.Name(), Error: fmt.Errorf("%v: %v", err, string(respdata))}
return nil
}
if err := json.NewDecoder(bytes.NewReader(respdata)).Decode(quakeResponse); err != nil {
errx := errorutil.NewWithErr(err)
// quake has different json format for error messages try to unmarshal it in map and print map
var errMap map[string]interface{}
if err := json.NewDecoder(bytes.NewReader(respdata)).Decode(&errMap); err == nil {
errx = errx.Msgf("failed to decode quake response: %v", errMap)
} else {
errx = errx.Msgf("failed to decode quake response: %s", string(respdata))
}
results <- sources.Result{Source: agent.Name(), Error: errx}
return nil
}
for _, quakeResult := range quakeResponse.Data {
result := sources.Result{Source: agent.Name()}
result.IP = quakeResult.IP
result.Port = quakeResult.Port
result.Host = quakeResult.Hostname
raw, _ := json.Marshal(result)
result.Raw = raw
results <- result
}
return quakeResponse
}
func (agent *Agent) queryURL(session *sources.Session, URL string, quakeRequest *Request) (*http.Response, error) {
body, err := json.Marshal(quakeRequest)
if err != nil {
return nil, err
}
request, err := sources.NewHTTPRequest(
http.MethodPost,
URL,
bytes.NewReader(body),
)
if err != nil {
return nil, err
}
request.Header.Set("Content-Type", "application/json")
request.Header.Set("X-QuakeToken", session.Keys.QuakeToken)
return session.Do(request, agent.Name())
}