-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from Buzz2d0/PR#5
feat: add mix payload with url package
- Loading branch information
Showing
4 changed files
with
256 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// Package mix used to mix payload with different rules and scopes | ||
package mix | ||
|
||
import ( | ||
"net/url" | ||
"path" | ||
"strings" | ||
|
||
"github.com/gokitx/pkgs/urlx" | ||
) | ||
|
||
func Payloads(u url.URL, payloads []string, rules []Rule, scopes []Scope) []url.URL { | ||
var urls []url.URL | ||
for _, scope := range scopes { | ||
switch scope { | ||
case ScopeQuery: | ||
urls = append(urls, mixQuery(u, payloads, rules)...) | ||
case ScopePath: | ||
urls = append(urls, mixPath(u, payloads, rules)...) | ||
case ScopeFragment: | ||
urls = append(urls, mixFragment(u, payloads, rules)...) | ||
} | ||
} | ||
return urls | ||
} | ||
|
||
func mixQuery(u url.URL, payloads []string, rules []Rule) []url.URL { | ||
if len(u.Query()) == 0 { | ||
return nil | ||
} | ||
baseQuery := u.Query() | ||
urls := make([]url.URL, len(payloads)*len(rules)*len(baseQuery)) | ||
|
||
var index int | ||
for _, payload := range payloads { | ||
for key := range baseQuery { | ||
for _, rule := range rules { | ||
u.RawQuery = generateQueryWithRule( | ||
urlx.CloneUrlValues(baseQuery), | ||
key, payload, rule, | ||
).Encode() | ||
urls[index] = u | ||
index++ | ||
} | ||
} | ||
} | ||
return urls | ||
} | ||
|
||
func generateQueryWithRule(query url.Values, key, payload string, rule Rule) url.Values { | ||
switch rule { | ||
case RuleAppendPrefix: | ||
query.Set(key, payload+query.Get(key)) | ||
return query | ||
case RuleAppendSuffix: | ||
query.Set(key, query.Get(key)+payload) | ||
return query | ||
case RuleReplace: | ||
query.Set(key, payload) | ||
return query | ||
} | ||
return query | ||
} | ||
|
||
func mixPath(u url.URL, payloads []string, rules []Rule) []url.URL { | ||
var urls []url.URL | ||
paths := strings.Split(u.Path, "/") | ||
if len(paths) <= 1 { | ||
return nil | ||
} | ||
for _, payload := range payloads { | ||
for index := range paths { | ||
for _, rule := range rules { | ||
if paths[index] == "" { | ||
continue | ||
} | ||
brefore := paths[index] | ||
paths[index] = generateStrWithRule(brefore, payload, rule) | ||
u.Path = path.Join(paths...) | ||
paths[index] = brefore | ||
urls = append(urls, u) | ||
} | ||
} | ||
} | ||
return urls | ||
} | ||
|
||
func generateStrWithRule(old, payload string, rule Rule) string { | ||
switch rule { | ||
case RuleAppendPrefix: | ||
return payload + old | ||
case RuleAppendSuffix: | ||
return old + payload | ||
case RuleReplace: | ||
return payload | ||
} | ||
return old | ||
} | ||
|
||
func mixFragment(u url.URL, payloads []string, rules []Rule) []url.URL { | ||
var urls []url.URL | ||
if u.Fragment == "" { | ||
return nil | ||
} | ||
fragment := u.Fragment | ||
for _, payload := range payloads { | ||
for _, rule := range rules { | ||
u.Fragment = generateStrWithRule(fragment, payload, rule) | ||
urls = append(urls, u) | ||
} | ||
} | ||
return urls | ||
} | ||
|
||
// mixFilter decides whether a payload or url is allowed to be mixed or not. | ||
// TODO: filter numeric or string types | ||
type mixFilter int | ||
|
||
const ( | ||
FilterNumeric mixFilter = iota + 1 | ||
FilterString | ||
FilterIP | ||
FilterDomain | ||
FilterURI | ||
FilterEmail | ||
) | ||
|
||
type Rule int | ||
|
||
const ( | ||
// RuleAppendPrefix appends the payload to the beginning of the string | ||
RuleAppendPrefix Rule = iota + 1 | ||
// RuleAppendSuffix appends the payload to the end of the string | ||
RuleAppendSuffix | ||
// RuleReplace replaces the string with the payload | ||
RuleReplace | ||
) | ||
|
||
var DefaultMixRules = []Rule{RuleAppendPrefix, RuleAppendSuffix, RuleReplace} | ||
|
||
type Scope int | ||
|
||
const ( | ||
ScopeQuery Scope = iota + 1 | ||
ScopePath | ||
ScopeFragment | ||
) | ||
|
||
var DefaultScopes = []Scope{ScopeQuery, ScopeFragment} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package mix | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
var urlTestCases = []struct { | ||
urlOBJ url.URL | ||
}{ | ||
{ | ||
urlOBJ: url.URL{ | ||
Scheme: "https", | ||
Host: "www.hackerone.com", | ||
Path: "/pathA/pathB/pathC", | ||
RawQuery: "queryA=111&queryB=222", | ||
Fragment: "fragment", | ||
}, | ||
}, | ||
} | ||
|
||
var payloads = []string{ | ||
"moond4rk", | ||
"buzz2d0", | ||
} | ||
|
||
func TestMixPayloads(t *testing.T) { | ||
t.Parallel() | ||
var urls []url.URL | ||
for _, testCase := range urlTestCases { | ||
urls = Payloads(testCase.urlOBJ, payloads, DefaultMixRules, DefaultScopes) | ||
} | ||
for _, v := range urls { | ||
fmt.Println(v.String()) | ||
} | ||
} | ||
|
||
func TestPathMixPayloads(t *testing.T) { | ||
t.Parallel() | ||
var urls []url.URL | ||
for _, testCase := range urlTestCases { | ||
urls = Payloads(testCase.urlOBJ, payloads, DefaultMixRules, []Scope{ScopePath}) | ||
} | ||
for _, v := range urls { | ||
fmt.Println(v.String()) | ||
} | ||
} | ||
|
||
func TestMixQuery(t *testing.T) { | ||
t.Parallel() | ||
var urls []url.URL | ||
var queryIndex int | ||
for _, tc := range urlTestCases { | ||
queryIndex += len(tc.urlOBJ.Query()) | ||
urls = append(urls, mixQuery(tc.urlOBJ, payloads, DefaultMixRules)...) | ||
} | ||
if len(urls) != len(urlTestCases)*len(payloads)*len(DefaultMixRules)*queryIndex { | ||
t.Errorf("Expected %d urls, got %d", len(urlTestCases)*len(payloads)*len(DefaultMixRules)*queryIndex, len(urls)) | ||
} | ||
} | ||
|
||
func TestMixPath(t *testing.T) { | ||
t.Parallel() | ||
var urls []url.URL | ||
pathIndex := 0 | ||
for _, tc := range urlTestCases { | ||
for _, p := range strings.Split(tc.urlOBJ.Path, "/") { | ||
if p != "" { | ||
pathIndex++ | ||
} | ||
} | ||
urls = append(urls, mixPath(tc.urlOBJ, payloads, DefaultMixRules)...) | ||
} | ||
if len(urls) != len(urlTestCases)*len(payloads)*len(DefaultMixRules)*pathIndex { | ||
t.Errorf("Expected %d urls, got %d", len(urlTestCases)*len(payloads)*len(DefaultMixRules)*pathIndex, len(urls)) | ||
} | ||
} | ||
|
||
func TestMixFragment(t *testing.T) { | ||
t.Parallel() | ||
var urls []url.URL | ||
var index int | ||
for _, tc := range urlTestCases { | ||
if tc.urlOBJ.Fragment != "" { | ||
index++ | ||
} | ||
urls = append(urls, mixFragment(tc.urlOBJ, payloads, DefaultMixRules)...) | ||
} | ||
if len(urls) != len(urlTestCases)*len(payloads)*len(DefaultMixRules)*index { | ||
t.Errorf("Expected %d urls, got %d", len(urlTestCases)*len(payloads)*len(DefaultMixRules), len(urls)) | ||
} | ||
} |