feat: implement duckduckgo search
parent
9d1d5db24a
commit
860b09bcf8
|
@ -1,7 +1,14 @@
|
||||||
package dorkgen
|
package dorkgen
|
||||||
|
|
||||||
import "github.com/sundowndev/dorkgen/googlesearch"
|
import (
|
||||||
|
"github.com/sundowndev/dorkgen/duckduckgo"
|
||||||
|
"github.com/sundowndev/dorkgen/googlesearch"
|
||||||
|
)
|
||||||
|
|
||||||
func NewGoogleSearch() *googlesearch.GoogleSearch {
|
func NewGoogleSearch() *googlesearch.GoogleSearch {
|
||||||
return googlesearch.New()
|
return googlesearch.New()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewDuckDuckGo() *duckduckgo.DuckDuckGo {
|
||||||
|
return duckduckgo.New()
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package dorkgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
assertion "github.com/stretchr/testify/assert"
|
assertion "github.com/stretchr/testify/assert"
|
||||||
|
"github.com/sundowndev/dorkgen/duckduckgo"
|
||||||
"github.com/sundowndev/dorkgen/googlesearch"
|
"github.com/sundowndev/dorkgen/googlesearch"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -14,4 +15,10 @@ func TestInit(t *testing.T) {
|
||||||
|
|
||||||
assert.IsType(&googlesearch.GoogleSearch{}, dork, "they should be equal")
|
assert.IsType(&googlesearch.GoogleSearch{}, dork, "they should be equal")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("should create a DuckDuckGo instance", func(t *testing.T) {
|
||||||
|
dork := NewDuckDuckGo()
|
||||||
|
|
||||||
|
assert.IsType(&duckduckgo.DuckDuckGo{}, dork, "they should be equal")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
package duckduckgo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
searchURL = "https://www.google.com/search"
|
||||||
|
siteTag = "site:"
|
||||||
|
urlTag = "inurl:"
|
||||||
|
filetypeTag = "filetype:"
|
||||||
|
extTag = "ext:"
|
||||||
|
excludeTag = "-"
|
||||||
|
intitleTag = "intitle:"
|
||||||
|
intextTag = "intext:"
|
||||||
|
operatorOr = "|"
|
||||||
|
operatorAnd = "+"
|
||||||
|
allInURLTag = "allinurl:"
|
||||||
|
locationTag = "region:"
|
||||||
|
feedTag = "feed:"
|
||||||
|
hasfeedTag = "hasfeed:"
|
||||||
|
languageTag = "language:"
|
||||||
|
allintitleTag = "allintitle:"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DuckDuckGo is the Google search implementation for Dorkgen
|
||||||
|
type DuckDuckGo struct {
|
||||||
|
tags []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new instance of DuckDuckGo
|
||||||
|
func New() *DuckDuckGo {
|
||||||
|
return &DuckDuckGo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DuckDuckGo) concat(tag string, value string, quotes bool) string {
|
||||||
|
if quotes {
|
||||||
|
return tag + "\"" + value + "\""
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag + value
|
||||||
|
}
|
||||||
|
|
||||||
|
// String converts all tags to a single request
|
||||||
|
func (d *DuckDuckGo) String() string {
|
||||||
|
return strings.Join(d.tags, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryValues returns search request as URL values
|
||||||
|
func (d *DuckDuckGo) QueryValues() url.Values {
|
||||||
|
tags := strings.Join(d.tags, " ")
|
||||||
|
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("q", tags)
|
||||||
|
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL converts tags to an encoded Google Search URL
|
||||||
|
func (d *DuckDuckGo) URL() string {
|
||||||
|
baseURL, _ := url.Parse(searchURL)
|
||||||
|
|
||||||
|
baseURL.RawQuery = d.QueryValues().Encode()
|
||||||
|
|
||||||
|
return baseURL.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Site specifically searches that particular site and lists all the results for that site.
|
||||||
|
func (d *DuckDuckGo) Site(site string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(siteTag, site, false))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or puts an OR operator in the request
|
||||||
|
func (d *DuckDuckGo) Or() *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, operatorOr)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// And puts an AND operator in the request
|
||||||
|
func (d *DuckDuckGo) And() *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, operatorAnd)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intext searches for the occurrences of keywords all at once or one at a time.
|
||||||
|
func (d *DuckDuckGo) Intext(text string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(intextTag, text, true))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inurl searches for a URL matching one of the keywords.
|
||||||
|
func (d *DuckDuckGo) Inurl(url string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(urlTag, url, true))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filetype searches for a particular filetype mentioned in the query.
|
||||||
|
func (d *DuckDuckGo) Filetype(filetype string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(filetypeTag, filetype, true))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ext searches for a particular file extension mentioned in the query.
|
||||||
|
func (d *DuckDuckGo) Ext(ext string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(extTag, ext, false))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude excludes some results.
|
||||||
|
func (d *DuckDuckGo) Exclude(tags *DuckDuckGo) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(excludeTag, tags.String(), false))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group isolate tags between parentheses
|
||||||
|
func (d *DuckDuckGo) Group(tags *DuckDuckGo) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, "("+tags.String()+")")
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intitle searches for occurrences of keywords in title all or one.
|
||||||
|
func (d *DuckDuckGo) Intitle(value string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(intitleTag, value, true))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plain allows you to add additional values as string without any kind of formatting.
|
||||||
|
func (d *DuckDuckGo) Plain(value string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, value)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllInURL finds pages that include a specific keyword as part of their indexed URLs.
|
||||||
|
func (d *DuckDuckGo) AllInURL(value string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(allInURLTag, value, true))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Location searches for specific region.
|
||||||
|
// An iso location code is a short code for a country for example, Egypt is eg and USA is us.
|
||||||
|
// https://en.wikipedia.org/wiki/ISO_3166-1
|
||||||
|
func (d *DuckDuckGo) Location(isoCode string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(locationTag, isoCode, false))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed finds RSS feed related to search term (i.e. rss).
|
||||||
|
func (d *DuckDuckGo) Feed(feed string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(feedTag, feed, false))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasFeed finds webpages that contain both the term or terms for which you are querying and one or more RSS or Atom feeds.
|
||||||
|
func (d *DuckDuckGo) HasFeed(url string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(hasfeedTag, url, true))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Language returns websites that match the search term in a specified language.
|
||||||
|
func (d *DuckDuckGo) Language(lang string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(languageTag, lang, false))
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllInTitle finds pages that include a specific keyword as part of the indexed title tag.
|
||||||
|
func (d *DuckDuckGo) AllInTitle(value string) *DuckDuckGo {
|
||||||
|
d.tags = append(d.tags, d.concat(allintitleTag, value, true))
|
||||||
|
return d
|
||||||
|
}
|
|
@ -0,0 +1,218 @@
|
||||||
|
package duckduckgo_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/sundowndev/dorkgen/duckduckgo"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
assertion "github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dork *duckduckgo.DuckDuckGo
|
||||||
|
|
||||||
|
func TestInit(t *testing.T) {
|
||||||
|
assert := assertion.New(t)
|
||||||
|
|
||||||
|
t.Run("should convert to URL correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Site("example.com").
|
||||||
|
URL()
|
||||||
|
|
||||||
|
assert.Equal(result, "https://www.google.com/search?q=site%3Aexample.com", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should convert to string correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := fmt.Sprint(dork.Site("example.com"))
|
||||||
|
|
||||||
|
assert.Equal(result, "site:example.com", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should handle site tag correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Site("example.com").
|
||||||
|
String()
|
||||||
|
|
||||||
|
assert.Equal(result, "site:example.com", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should handle intext tag correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Intext("text").
|
||||||
|
String()
|
||||||
|
|
||||||
|
assert.Equal(result, "intext:\"text\"", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should handle inurl tag correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Inurl("index.php").
|
||||||
|
String()
|
||||||
|
|
||||||
|
assert.Equal(result, "inurl:\"index.php\"", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should handle filetype tag correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Filetype("pdf").
|
||||||
|
String()
|
||||||
|
|
||||||
|
assert.Equal(result, "filetype:\"pdf\"", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
//t.Run("should handle AllInURL tag correctly", func(t *testing.T) {
|
||||||
|
// dork = duckduckgo.New()
|
||||||
|
//
|
||||||
|
// result := dork.
|
||||||
|
// Cache("www.google.com").
|
||||||
|
// String()
|
||||||
|
//
|
||||||
|
// assert.Equal(result, "cache:\"www.google.com\"", "they should be equal")
|
||||||
|
//})
|
||||||
|
|
||||||
|
//t.Run("should handle Location tag correctly", func(t *testing.T) {
|
||||||
|
// dork = duckduckgo.New()
|
||||||
|
//
|
||||||
|
// result := dork.
|
||||||
|
// Related("www.google.com").
|
||||||
|
// String()
|
||||||
|
//
|
||||||
|
// assert.Equal(result, "related:\"www.google.com\"", "they should be equal")
|
||||||
|
//})
|
||||||
|
|
||||||
|
//t.Run("should handle Feed tag correctly", func(t *testing.T) {
|
||||||
|
// dork = duckduckgo.New()
|
||||||
|
//
|
||||||
|
// result := dork.
|
||||||
|
// Related("www.google.com").
|
||||||
|
// String()
|
||||||
|
//
|
||||||
|
// assert.Equal(result, "related:\"www.google.com\"", "they should be equal")
|
||||||
|
//})
|
||||||
|
|
||||||
|
//t.Run("should handle HasFeed tag correctly", func(t *testing.T) {
|
||||||
|
// dork = duckduckgo.New()
|
||||||
|
//
|
||||||
|
// result := dork.
|
||||||
|
// Related("www.google.com").
|
||||||
|
// String()
|
||||||
|
//
|
||||||
|
// assert.Equal(result, "related:\"www.google.com\"", "they should be equal")
|
||||||
|
//})
|
||||||
|
|
||||||
|
//t.Run("should handle Language tag correctly", func(t *testing.T) {
|
||||||
|
// dork = duckduckgo.New()
|
||||||
|
//
|
||||||
|
// result := dork.
|
||||||
|
// Related("www.google.com").
|
||||||
|
// String()
|
||||||
|
//
|
||||||
|
// assert.Equal(result, "related:\"www.google.com\"", "they should be equal")
|
||||||
|
//})
|
||||||
|
|
||||||
|
//t.Run("should handle AllInTitle tag correctly", func(t *testing.T) {
|
||||||
|
// dork = duckduckgo.New()
|
||||||
|
//
|
||||||
|
// result := dork.
|
||||||
|
// Related("www.google.com").
|
||||||
|
// String()
|
||||||
|
//
|
||||||
|
// assert.Equal(result, "related:\"www.google.com\"", "they should be equal")
|
||||||
|
//})
|
||||||
|
|
||||||
|
t.Run("should handle ext tag correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Ext("(doc | pdf | xls | txt | xml)").
|
||||||
|
String()
|
||||||
|
|
||||||
|
assert.Equal(result, "ext:(doc | pdf | xls | txt | xml)", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should handle exclude tag correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Exclude(duckduckgo.New().Plain("html")).
|
||||||
|
Exclude(duckduckgo.New().Plain("htm")).
|
||||||
|
Exclude(duckduckgo.New().Plain("php")).
|
||||||
|
Exclude(duckduckgo.New().Plain("md5sums")).
|
||||||
|
String()
|
||||||
|
|
||||||
|
assert.Equal(result, "-html -htm -php -md5sums", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should handle 'OR' tag correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Site("facebook.com").
|
||||||
|
Or().
|
||||||
|
Site("twitter.com").
|
||||||
|
String()
|
||||||
|
|
||||||
|
assert.Equal(result, "site:facebook.com | site:twitter.com", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should handle 'AND' tag correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Intitle("facebook").
|
||||||
|
And().
|
||||||
|
Intitle("twitter").
|
||||||
|
String()
|
||||||
|
|
||||||
|
assert.Equal(result, "intitle:\"facebook\" + intitle:\"twitter\"", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should handle group tag correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Site("linkedin.com").
|
||||||
|
Group(duckduckgo.New().Intext("1").Or().Intext("2")).
|
||||||
|
String()
|
||||||
|
|
||||||
|
assert.Equal(result, "site:linkedin.com (intext:\"1\" | intext:\"2\")", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should handle group tag correctly", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Site("linkedin.com").
|
||||||
|
Group(duckduckgo.New().Intext("1").Or().Intext("2")).
|
||||||
|
Intitle("jordan").
|
||||||
|
String()
|
||||||
|
|
||||||
|
assert.Equal(result, "site:linkedin.com (intext:\"1\" | intext:\"2\") intitle:\"jordan\"", "they should be equal")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should return URL values", func(t *testing.T) {
|
||||||
|
dork = duckduckgo.New()
|
||||||
|
|
||||||
|
result := dork.
|
||||||
|
Site("linkedin.com").
|
||||||
|
Group(duckduckgo.New().Intext("1").Or().Intext("2")).
|
||||||
|
Intitle("jordan").
|
||||||
|
QueryValues()
|
||||||
|
|
||||||
|
assert.Equal(url.Values{
|
||||||
|
"q": []string{"site:linkedin.com (intext:\"1\" | intext:\"2\") intitle:\"jordan\""},
|
||||||
|
}, result, "they should be equal")
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue