Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/passive/sources.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/projectdiscovery/subfinder/v2/pkg/subscraping/sources/digitorus"
"github.com/projectdiscovery/subfinder/v2/pkg/subscraping/sources/dnsdb"
"github.com/projectdiscovery/subfinder/v2/pkg/subscraping/sources/dnsdumpster"
"github.com/projectdiscovery/subfinder/v2/pkg/subscraping/sources/domainsproject"
"github.com/projectdiscovery/subfinder/v2/pkg/subscraping/sources/dnsrepo"
"github.com/projectdiscovery/subfinder/v2/pkg/subscraping/sources/driftnet"
"github.com/projectdiscovery/subfinder/v2/pkg/subscraping/sources/facebook"
Expand Down Expand Up @@ -71,6 +72,7 @@ var AllSources = [...]subscraping.Source{
&digitorus.Source{},
&dnsdb.Source{},
&dnsdumpster.Source{},
&domainsproject.Source{},
&dnsrepo.Source{},
&driftnet.Source{},
&fofa.Source{},
Expand Down
131 changes: 131 additions & 0 deletions pkg/subscraping/sources/domainsproject/domainsproject.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Package domainsproject logic
package domainsproject

import (
"context"
"fmt"
"strings"
"time"

jsoniter "github.com/json-iterator/go"

"github.com/projectdiscovery/subfinder/v2/pkg/subscraping"
)

// Source is the passive scraping agent
type Source struct {
apiKeys []apiKey
timeTaken time.Duration
errors int
results int
skipped bool
}

type apiKey struct {
username string
password string
}

type domainsProjectResponse struct {
Domains []string `json:"domains"`
Error string `json:"error"`
}

// Run function returns all subdomains found with the service
func (s *Source) Run(ctx context.Context, domain string, session *subscraping.Session) <-chan subscraping.Result {
results := make(chan subscraping.Result)
s.errors = 0
s.results = 0

go func() {
defer func(startTime time.Time) {
s.timeTaken = time.Since(startTime)
close(results)
}(time.Now())

randomApiKey := subscraping.PickRandom(s.apiKeys, s.Name())
if randomApiKey.username == "" || randomApiKey.password == "" {
s.skipped = true
return
}

searchURL := fmt.Sprintf("https://api.domainsproject.org/api/tld/search?domain=%s", domain)
resp, err := session.HTTPRequest(
ctx,
"GET",
searchURL,
"",
nil,
nil,
subscraping.BasicAuth{Username: randomApiKey.username, Password: randomApiKey.password},
)
if err != nil {
session.DiscardHTTPResponse(resp)
return
}

defer func() {
if err := resp.Body.Close(); err != nil {
results <- subscraping.Result{Source: s.Name(), Type: subscraping.Error, Error: err}
s.errors++
}
}()

var response domainsProjectResponse
err = jsoniter.NewDecoder(resp.Body).Decode(&response)
if err != nil {
results <- subscraping.Result{Source: s.Name(), Type: subscraping.Error, Error: err}
s.errors++
return
}

if response.Error != "" {
results <- subscraping.Result{
Source: s.Name(), Type: subscraping.Error, Error: fmt.Errorf("%v", response.Error),
}
s.errors++
return
}

for _, subdomain := range response.Domains {
if !strings.HasPrefix(subdomain, ".") {
results <- subscraping.Result{Source: s.Name(), Type: subscraping.Subdomain, Value: subdomain}
s.results++
}
}
}()

return results
}

// Name returns the name of the source
func (s *Source) Name() string {
return "domainsproject"
}

func (s *Source) IsDefault() bool {
return true
}

func (s *Source) HasRecursiveSupport() bool {
return false
}

func (s *Source) NeedsKey() bool {
return true
}

func (s *Source) AddApiKeys(keys []string) {
s.apiKeys = subscraping.CreateApiKeys(keys, func(k, v string) apiKey {
return apiKey{k, v}
})
}

func (s *Source) Statistics() subscraping.Statistics {
return subscraping.Statistics{
Errors: s.errors,
Results: s.results,
TimeTaken: s.timeTaken,
Skipped: s.skipped,
}
}