mirror of
https://github.com/projectdiscovery/httpx.git
synced 2024-11-28 22:01:28 +03:00
various fixes and features
This commit is contained in:
parent
077cc70226
commit
bac670a949
@ -17,16 +17,17 @@ import (
|
||||
"github.com/projectdiscovery/httpx/common/customheader"
|
||||
customport "github.com/projectdiscovery/httpx/common/customports"
|
||||
"github.com/projectdiscovery/httpx/common/fileutil"
|
||||
"github.com/projectdiscovery/httpx/common/httputilz"
|
||||
"github.com/projectdiscovery/httpx/common/httpx"
|
||||
"github.com/projectdiscovery/httpx/common/iputil"
|
||||
"github.com/projectdiscovery/httpx/common/slice"
|
||||
"github.com/projectdiscovery/httpx/common/stringz"
|
||||
"github.com/projectdiscovery/mapcidr"
|
||||
"github.com/remeh/sizedwaitgroup"
|
||||
)
|
||||
|
||||
func main() {
|
||||
options := ParseOptions()
|
||||
options.validateOptions()
|
||||
|
||||
httpxOptions := httpx.DefaultOptions
|
||||
httpxOptions.Timeout = time.Duration(options.Timeout) * time.Second
|
||||
@ -34,11 +35,12 @@ func main() {
|
||||
httpxOptions.FollowRedirects = options.FollowRedirects
|
||||
httpxOptions.FollowHostRedirects = options.FollowHostRedirects
|
||||
httpxOptions.HttpProxy = options.HttpProxy
|
||||
httpxOptions.Unsafe = options.Unsafe
|
||||
|
||||
var key, value string
|
||||
httpxOptions.CustomHeaders = make(map[string]string)
|
||||
for _, customHeader := range options.CustomHeaders {
|
||||
tokens := strings.Split(customHeader, ":")
|
||||
tokens := strings.SplitN(customHeader, ":", 2)
|
||||
// if it's an invalid header skip it
|
||||
if len(tokens) < 2 {
|
||||
continue
|
||||
@ -55,6 +57,27 @@ func main() {
|
||||
}
|
||||
|
||||
var scanopts scanOptions
|
||||
|
||||
if options.InputRawRequest != "" {
|
||||
var rawRequest []byte
|
||||
rawRequest, err = ioutil.ReadFile(options.InputRawRequest)
|
||||
if err != nil {
|
||||
gologger.Fatalf("Could not read raw request from '%s': %s\n", options.InputRawRequest, err)
|
||||
}
|
||||
|
||||
rrMethod, rrPath, rrHeaders, rrBody, err := httputilz.ParseRequest(string(rawRequest))
|
||||
if err != nil {
|
||||
gologger.Fatalf("Could not parse raw request: %s\n", err)
|
||||
}
|
||||
scanopts.Method = rrMethod
|
||||
scanopts.RequestURI = rrPath
|
||||
for name, value := range rrHeaders {
|
||||
httpxOptions.CustomHeaders[name] = value
|
||||
}
|
||||
scanopts.RequestBody = rrBody
|
||||
options.rawRequest = string(rawRequest)
|
||||
}
|
||||
|
||||
scanopts.Method = options.Method
|
||||
protocol := "https"
|
||||
scanopts.VHost = options.VHost
|
||||
@ -64,14 +87,21 @@ func main() {
|
||||
scanopts.OutputContentLength = options.ContentLength
|
||||
scanopts.StoreResponse = options.StoreResponse
|
||||
scanopts.StoreResponseDirectory = options.StoreResponseDir
|
||||
scanopts.Method = options.Method
|
||||
if options.Method != "" {
|
||||
scanopts.Method = options.Method
|
||||
}
|
||||
scanopts.OutputServerHeader = options.OutputServerHeader
|
||||
scanopts.OutputWithNoColor = options.NoColor
|
||||
scanopts.ResponseInStdout = options.responseInStdout
|
||||
scanopts.OutputWebSocket = options.OutputWebSocket
|
||||
scanopts.TlsProbe = options.TLSProbe
|
||||
scanopts.RequestURI = options.RequestURI
|
||||
scanopts.CspProbe = options.CSPProbe
|
||||
if options.RequestURI != "" {
|
||||
scanopts.RequestURI = options.RequestURI
|
||||
}
|
||||
scanopts.OutputContentType = options.OutputContentType
|
||||
scanopts.RequestBody = options.RequestBody
|
||||
scanopts.Unsafe = options.Unsafe
|
||||
|
||||
// Try to create output folder if it doesnt exist
|
||||
if options.StoreResponse && !fileutil.FolderExists(options.StoreResponseDir) {
|
||||
@ -98,6 +128,7 @@ func main() {
|
||||
}
|
||||
for r := range output {
|
||||
if r.err != nil {
|
||||
//log.Println(r.err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -173,6 +204,12 @@ func process(t string, wg *sizedwaitgroup.SizedWaitGroup, hp *httpx.HTTPX, proto
|
||||
process(tt, wg, hp, protocol, scanopts, output)
|
||||
}
|
||||
}
|
||||
if scanopts.CspProbe && r.CspData != nil {
|
||||
scanopts.CspProbe = false
|
||||
for _, tt := range r.CspData.Domains {
|
||||
process(tt, wg, hp, protocol, scanopts, output)
|
||||
}
|
||||
}
|
||||
}(target)
|
||||
}
|
||||
|
||||
@ -217,7 +254,7 @@ func targets(target string) chan string {
|
||||
|
||||
// test if the target is a cidr
|
||||
if iputil.IsCidr(target) {
|
||||
cidrIps, err := iputil.Ips(target)
|
||||
cidrIps, err := mapcidr.Ips(target)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -237,7 +274,7 @@ type scanOptions struct {
|
||||
VHost bool
|
||||
OutputTitle bool
|
||||
OutputStatusCode bool
|
||||
OutputLocation bool
|
||||
OutputLocation bool
|
||||
OutputContentLength bool
|
||||
StoreResponse bool
|
||||
StoreResponseDirectory string
|
||||
@ -246,8 +283,11 @@ type scanOptions struct {
|
||||
OutputWithNoColor bool
|
||||
ResponseInStdout bool
|
||||
TlsProbe bool
|
||||
CspProbe bool
|
||||
RequestURI string
|
||||
OutputContentType bool
|
||||
RequestBody string
|
||||
Unsafe bool
|
||||
}
|
||||
|
||||
func analyze(hp *httpx.HTTPX, protocol string, domain string, port int, scanopts *scanOptions) Result {
|
||||
@ -255,7 +295,7 @@ func analyze(hp *httpx.HTTPX, protocol string, domain string, port int, scanopts
|
||||
retry:
|
||||
URL := fmt.Sprintf("%s://%s%s", protocol, domain, scanopts.RequestURI)
|
||||
if port > 0 {
|
||||
URL = fmt.Sprintf("%s:%d", URL, port)
|
||||
URL = fmt.Sprintf("%s://%s:%d%s", protocol, domain, port, scanopts.RequestURI)
|
||||
}
|
||||
|
||||
req, err := hp.NewRequest(scanopts.Method, URL)
|
||||
@ -264,6 +304,9 @@ retry:
|
||||
}
|
||||
|
||||
hp.SetCustomHeaders(req, hp.CustomHeaders)
|
||||
if scanopts.RequestBody != "" {
|
||||
req.Body = ioutil.NopCloser(strings.NewReader(scanopts.RequestBody))
|
||||
}
|
||||
|
||||
resp, err := hp.Do(req)
|
||||
if err != nil {
|
||||
@ -381,7 +424,11 @@ retry:
|
||||
|
||||
// store responses in directory
|
||||
if scanopts.StoreResponse {
|
||||
var domainFile = strings.Replace(domain+scanopts.RequestURI, "/", "_", -1) + ".txt"
|
||||
domainFile := fmt.Sprintf("%s%s", domain, scanopts.RequestURI)
|
||||
if port > 0 {
|
||||
domainFile = fmt.Sprintf("%s.%d%s", domain, port, scanopts.RequestURI)
|
||||
}
|
||||
domainFile = strings.Replace(domainFile, "/", "_", -1) + ".txt"
|
||||
responsePath := path.Join(scanopts.StoreResponseDirectory, domainFile)
|
||||
err := ioutil.WriteFile(responsePath, []byte(resp.Raw), 0644)
|
||||
if err != nil {
|
||||
@ -402,6 +449,7 @@ retry:
|
||||
Response: serverResponseRaw,
|
||||
WebSocket: isWebSocket,
|
||||
TlsData: resp.TlsData,
|
||||
CspData: resp.CspData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,6 +468,7 @@ type Result struct {
|
||||
WebSocket bool `json:"websocket,omitempty"`
|
||||
ContentType string `json:"content-type,omitempty"`
|
||||
TlsData *httpx.TlsData `json:"tls,omitempty"`
|
||||
CspData *httpx.CspData `json:"csp,omitempty"`
|
||||
}
|
||||
|
||||
// JSON the result
|
||||
@ -433,7 +482,6 @@ func (r *Result) JSON() string {
|
||||
|
||||
// Options contains configuration options for chaos client.
|
||||
type Options struct {
|
||||
RawRequestFile string
|
||||
VHost bool
|
||||
Smuggling bool
|
||||
ExtractTitle bool
|
||||
@ -463,6 +511,7 @@ type Options struct {
|
||||
responseInStdout bool
|
||||
FollowHostRedirects bool
|
||||
TLSProbe bool
|
||||
CSPProbe bool
|
||||
RequestURI string
|
||||
OutputContentType bool
|
||||
OutputMatchStatusCode string
|
||||
@ -473,6 +522,10 @@ type Options struct {
|
||||
filterStatusCode []int
|
||||
OutputFilterContentLength string
|
||||
filterContentLength []int
|
||||
InputRawRequest string
|
||||
rawRequest string
|
||||
Unsafe bool
|
||||
RequestBody string
|
||||
}
|
||||
|
||||
// ParseOptions parses the command line options for application
|
||||
@ -497,7 +550,7 @@ func ParseOptions() *Options {
|
||||
flag.StringVar(&options.HttpProxy, "http-proxy", "", "HTTP Proxy, eg http://127.0.0.1:8080")
|
||||
flag.BoolVar(&options.JSONOutput, "json", false, "JSON Output")
|
||||
flag.StringVar(&options.InputFile, "l", "", "File containing domains")
|
||||
flag.StringVar(&options.Method, "x", "GET", "Request Method")
|
||||
flag.StringVar(&options.Method, "x", "", "Request Method")
|
||||
flag.BoolVar(&options.Silent, "silent", false, "Silent mode")
|
||||
flag.BoolVar(&options.Version, "version", false, "Show version of httpx")
|
||||
flag.BoolVar(&options.Verbose, "verbose", false, "Verbose Mode")
|
||||
@ -506,12 +559,16 @@ func ParseOptions() *Options {
|
||||
flag.BoolVar(&options.OutputWebSocket, "websocket", false, "Prints out if the server exposes a websocket")
|
||||
flag.BoolVar(&options.responseInStdout, "response-in-json", false, "Server response directly in the tool output (-json only)")
|
||||
flag.BoolVar(&options.TLSProbe, "tls-probe", false, "Send HTTP probes on the extracted TLS domains")
|
||||
flag.BoolVar(&options.CSPProbe, "csp-probe", false, "Send HTTP probes on the extracted CSP domains")
|
||||
flag.StringVar(&options.RequestURI, "path", "", "Request path/file (example '/api')")
|
||||
flag.BoolVar(&options.OutputContentType, "content-type", false, "Extracts content-type")
|
||||
flag.StringVar(&options.OutputMatchStatusCode, "mc", "", "Match status code")
|
||||
flag.StringVar(&options.OutputMatchStatusCode, "ml", "", "Match content length")
|
||||
flag.StringVar(&options.OutputFilterStatusCode, "fc", "", "Filter status code")
|
||||
flag.StringVar(&options.OutputFilterContentLength, "fl", "", "Filter content length")
|
||||
flag.StringVar(&options.InputRawRequest, "request", "", "File containing raw request")
|
||||
flag.BoolVar(&options.Unsafe, "unsafe", false, "Send raw requests skipping golang normalization")
|
||||
flag.StringVar(&options.RequestBody, "body", "", "Request Body")
|
||||
flag.Parse()
|
||||
|
||||
// Read the inputs and configure the logging
|
||||
@ -534,6 +591,10 @@ func (options *Options) validateOptions() {
|
||||
gologger.Fatalf("File %s does not exist!\n", options.InputFile)
|
||||
}
|
||||
|
||||
if options.InputRawRequest != "" && !fileutil.FileExists(options.InputRawRequest) {
|
||||
gologger.Fatalf("File %s does not exist!\n", options.InputRawRequest)
|
||||
}
|
||||
|
||||
var err error
|
||||
if options.matchStatusCode, err = stringz.StringToSliceInt(options.OutputMatchStatusCode); err != nil {
|
||||
gologger.Fatalf("Invalid value for match status code option: %s\n", err)
|
||||
|
@ -1,9 +1,13 @@
|
||||
package httputilz
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/projectdiscovery/retryablehttp-go"
|
||||
)
|
||||
@ -29,3 +33,67 @@ func DumpResponse(resp *http.Response) (string, error) {
|
||||
raw, err := httputil.DumpResponse(resp, true)
|
||||
return string(raw), err
|
||||
}
|
||||
|
||||
// ParseRequest from raw string
|
||||
func ParseRequest(req string) (method string, path string, headers map[string]string, body string, err error) {
|
||||
headers = make(map[string]string)
|
||||
reader := bufio.NewReader(strings.NewReader(req))
|
||||
s, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not read request: %s", err)
|
||||
return
|
||||
}
|
||||
parts := strings.Split(s, " ")
|
||||
if len(parts) < 3 {
|
||||
err = fmt.Errorf("malformed request supplied")
|
||||
return
|
||||
}
|
||||
method = parts[0]
|
||||
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
line = strings.TrimSpace(line)
|
||||
|
||||
if err != nil || line == "" {
|
||||
break
|
||||
}
|
||||
|
||||
p := strings.SplitN(line, ":", 2)
|
||||
if len(p) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.EqualFold(p[0], "content-length") {
|
||||
continue
|
||||
}
|
||||
|
||||
p[0] = strings.TrimSpace(p[0])
|
||||
p[1] = strings.TrimSpace(p[1])
|
||||
|
||||
headers[p[0]] = p[1]
|
||||
}
|
||||
|
||||
// Handle case with the full http url in path. In that case,
|
||||
// ignore any host header that we encounter and use the path as request URL
|
||||
if strings.HasPrefix(parts[1], "http") {
|
||||
var parsed *url.URL
|
||||
parsed, err = url.Parse(parts[1])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not parse request URL: %s", err)
|
||||
return
|
||||
}
|
||||
path = parts[1]
|
||||
headers["Host"] = parsed.Host
|
||||
} else {
|
||||
path = parts[1]
|
||||
}
|
||||
|
||||
// Set the request body
|
||||
b, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not read request body: %s", err)
|
||||
return
|
||||
}
|
||||
body = string(b)
|
||||
return
|
||||
}
|
||||
|
35
common/httpx/csp.go
Normal file
35
common/httpx/csp.go
Normal file
@ -0,0 +1,35 @@
|
||||
package httpx
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CspData struct {
|
||||
Domains []string `json:"domains,omitempty"`
|
||||
}
|
||||
|
||||
func (h *HTTPX) CspGrab(r *http.Response) *CspData {
|
||||
cspRaw := r.Header.Get("Content-Security-Policy")
|
||||
if cspRaw != "" {
|
||||
var domains []string
|
||||
rules := strings.Split(cspRaw, ";")
|
||||
for _, rule := range rules {
|
||||
// rule is like aa bb domain1 domain2 domain3
|
||||
tokens := strings.Split(rule, " ")
|
||||
// we extracts only potential domains
|
||||
for _, t := range tokens {
|
||||
if isPotentialDomain(t) {
|
||||
domains = append(domains, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
return &CspData{Domains: domains}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bare minimum conditions to filter potential domains
|
||||
func isPotentialDomain(s string) bool {
|
||||
return strings.Contains(s, ".") || strings.HasPrefix(s, "http")
|
||||
}
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"github.com/projectdiscovery/httpx/common/cache"
|
||||
"github.com/projectdiscovery/httpx/common/httputilz"
|
||||
"github.com/projectdiscovery/rawhttp"
|
||||
retryablehttp "github.com/projectdiscovery/retryablehttp-go"
|
||||
)
|
||||
|
||||
@ -92,7 +93,15 @@ func New(options *Options) (*HTTPX, error) {
|
||||
|
||||
// Do http request
|
||||
func (h *HTTPX) Do(req *retryablehttp.Request) (*Response, error) {
|
||||
httpresp, err := h.client.Do(req)
|
||||
var (
|
||||
httpresp *http.Response
|
||||
err error
|
||||
)
|
||||
if h.Options.Unsafe {
|
||||
httpresp, err = h.doUnsafe(req)
|
||||
} else {
|
||||
httpresp, err = h.client.Do(req)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -134,12 +143,21 @@ func (h *HTTPX) Do(req *retryablehttp.Request) (*Response, error) {
|
||||
// number of lines
|
||||
resp.Lines = len(strings.Split(respbodystr, "\n"))
|
||||
|
||||
// extracts TLS data if any
|
||||
resp.TlsData = h.TlsGrab(httpresp)
|
||||
if !h.Options.Unsafe {
|
||||
// extracts TLS data if any
|
||||
resp.TlsData = h.TlsGrab(httpresp)
|
||||
}
|
||||
|
||||
resp.CspData = h.CspGrab(httpresp)
|
||||
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
// Do http request
|
||||
func (h *HTTPX) doUnsafe(req *retryablehttp.Request) (*http.Response, error) {
|
||||
return rawhttp.Dor(req)
|
||||
}
|
||||
|
||||
// Verify the http calls and apply-cascade all the filters, as soon as one matches it returns true
|
||||
func (h *HTTPX) Verify(req *retryablehttp.Request) (bool, error) {
|
||||
resp, err := h.Do(req)
|
||||
|
@ -12,10 +12,11 @@ type Options struct {
|
||||
// RetryMax is the maximum number of retries
|
||||
RetryMax int
|
||||
|
||||
CustomHeaders map[string]string
|
||||
FollowRedirects bool
|
||||
CustomHeaders map[string]string
|
||||
FollowRedirects bool
|
||||
FollowHostRedirects bool
|
||||
DefaultUserAgent string
|
||||
DefaultUserAgent string
|
||||
Unsafe bool
|
||||
|
||||
HttpProxy string
|
||||
SocksProxy string
|
||||
@ -36,6 +37,7 @@ var DefaultOptions = Options{
|
||||
Threads: 25,
|
||||
Timeout: 30 * time.Second,
|
||||
RetryMax: 5,
|
||||
Unsafe: false,
|
||||
// VHOSTs options
|
||||
VHostIgnoreStatusCode: false,
|
||||
VHostIgnoreContentLength: true,
|
||||
|
@ -14,6 +14,7 @@ type Response struct {
|
||||
Words int
|
||||
Lines int
|
||||
TlsData *TlsData
|
||||
CspData *CspData
|
||||
}
|
||||
|
||||
// GetHeader value
|
||||
|
@ -16,27 +16,3 @@ func IsCidr(ip string) bool {
|
||||
func IsIP(ip string) bool {
|
||||
return net.ParseIP(ip) != nil
|
||||
}
|
||||
|
||||
// Ips of a cidr
|
||||
func Ips(cidr string) ([]string, error) {
|
||||
ip, ipnet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ips []string
|
||||
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
|
||||
ips = append(ips, ip.String())
|
||||
}
|
||||
// remove network address and broadcast address
|
||||
return ips[1 : len(ips)-1], nil
|
||||
}
|
||||
|
||||
func inc(ip net.IP) {
|
||||
for j := len(ip) - 1; j >= 0; j-- {
|
||||
ip[j]++
|
||||
if ip[j] > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
go.mod
17
go.mod
@ -1,17 +0,0 @@
|
||||
module github.com/projectdiscovery/httpx
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/coocood/freecache v1.1.1
|
||||
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/microcosm-cc/bluemonday v1.0.3
|
||||
github.com/miekg/dns v1.1.31
|
||||
github.com/projectdiscovery/gologger v1.0.1
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.1
|
||||
github.com/remeh/sizedwaitgroup v1.0.0
|
||||
github.com/rs/xid v1.2.1
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||
golang.org/x/text v0.3.3
|
||||
)
|
58
go.sum
58
go.sum
@ -1,58 +0,0 @@
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
|
||||
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
|
||||
github.com/coocood/freecache v1.1.1 h1:uukNF7QKCZEdZ9gAV7WQzvh0SbjwdMF6m3x3rxEkaPc=
|
||||
github.com/coocood/freecache v1.1.1/go.mod h1:OKrEjkGVoxZhyWAJoeFi5BMLUJm2Tit0kpGkIr7NGYY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
||||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
||||
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf h1:umfGUaWdFP2s6457fz1+xXYIWDxdGc7HdkLS9aJ1skk=
|
||||
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf/go.mod h1:V99KdStnMHZsvVOwIvhfcUzYgYkRZeQWUtumtL+SKxA=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.3 h1:EjVH7OqbU219kdm8acbveoclh2zZFqPJTJw6VUlTLAQ=
|
||||
github.com/microcosm-cc/bluemonday v1.0.3/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
|
||||
github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
|
||||
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/projectdiscovery/gologger v1.0.1 h1:FzoYQZnxz9DCvSi/eg5A6+ET4CQ0CDUs27l6Exr8zMQ=
|
||||
github.com/projectdiscovery/gologger v1.0.1/go.mod h1:Ok+axMqK53bWNwDSU1nTNwITLYMXMdZtRc8/y1c7sWE=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.1 h1:V7wUvsZNq1Rcz7+IlcyoyQlNwshuwptuBVYWw9lx8RE=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.1/go.mod h1:SrN6iLZilNG1X4neq1D+SBxoqfAF4nyzvmevkTkWsek=
|
||||
github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=
|
||||
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
|
||||
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
Loading…
Reference in New Issue
Block a user