Closed picatz closed 6 years ago
interface{}
(empty interface)Instead of a string
to encapsulate all successes, an empty interface (interface{}
) could be used. This would allow different types of results to provide practically any value; and it would be up to whoever is using that type to do the correct type assertion for what they want.
To be clear: I'm not saying this is the best way to go, or the worst.
package main
import "fmt"
import "encoding/json"
type Result struct {
Type string
Success interface{}
Failure error
}
func main() {
r := &Result{}
b := []byte(`{"Type":"example","Success":0,"Failure": null}`)
err := json.Unmarshal(b, r)
if err != nil {
panic(err)
}
r.Success = r.Success.(float64) + 1
fmt.Println(r.Success == float64(1))
}
true
Note: this also provides the least amount of friction for what is current implemented. Though I do not think that is the primary "selling point" for this approach. Just one aspect to consider. 👍
Implementing success as interface is really cool. It would also allow us to return an array of subdomains or individual subdomains.
@Ice3man543 Yeah, I agree. 👍
Example of dealing with results with different underly success types (string and slice of strings):
package main
import "fmt"
type Result struct {
Type string
Success interface{}
Failure error
}
var Example1 = &Result{Type: "example1", Success: "red.google.com"}
var Example2 = &Result{Type: "example2", Success: []string{"gree.google.com", "blue.google.com"}}
func main() {
examples := []*Result{Example1, Example2}
for _, example := range examples {
switch v := example.Success.(type) {
case string:
fmt.Printf("%v is a string\n", v)
case []string:
fmt.Printf("%v is a slice of strings\n", v)
default:
fmt.Printf("The type of v is unknown\n")
}
}
}
red.google.com is a string
[gree.google.com blue.google.com] is a slice of strings
Just another thought, maybe not the best one. 🤷♀️ What if there was a timestamp associated with the result? Something like Coordinated Universal Time (UTC).
In certain situations, this may be useful to have such as:
To allow for safe(?), concurrent access from multiple go routines on a single Result
, a simple RWMutex
synchronization primitive could be used.
Over in the investigate better result branch, I've implemented the following:
type Result struct {
sync.RWMutex
Timestamp time.Time
Type string
Success interface{}
Failure error
}
I made a simple
Result
type in the master branch of this repository. It's a very simple implementation that I would like to improve and ensure it's robust enough to handle what we want.The purpose of this specific type is to carry along the general information found during the subdomain enumeration process, encapsulating the necessary logic into a concise protocol/interface which other pieces of the internal system and work with.
At least that's what I was thinking when making it. 😹
Current Implementation
It currently looks like this (note: this is not used in SubFinder, just this repository):
Type
is astring
which is meant to have some sort of meaning based on whatever Result this is. Perhaps something like "baidu", "yahoo", "shodan", "google", or whatever otherSource
s are implemented now and in the future.Success
is also astring
which is mean to carry the meaningful value like "example.google.com" as a found subdomain.Failure
is meant to encapsulate the errors from the Source as a typical golangerror
.I'm fairly certain this can be improved to provide better... results 😉
Forgive my terrible puns, please.
Improving the Implementation
Note these are not in order or need to be done together in any way, just thinking:
Result
type could perhaps be turned into aninterface
instead of a struct that contains these current values.Success
for aResult
could be an empty interface and based on theType
, type assertion could happen where needed.