2020-08-05 17:14:10 +00:00
|
|
|
package main
|
|
|
|
|
2020-09-01 16:53:21 +00:00
|
|
|
import (
|
2020-11-16 13:18:14 +00:00
|
|
|
"io"
|
2020-10-06 17:07:48 +00:00
|
|
|
"math/rand"
|
2020-11-01 17:37:21 +00:00
|
|
|
"net/http"
|
2020-11-16 13:18:14 +00:00
|
|
|
"net/url"
|
2020-09-19 12:56:31 +00:00
|
|
|
"sort"
|
2020-09-01 16:53:21 +00:00
|
|
|
"strings"
|
2020-10-06 17:07:48 +00:00
|
|
|
"time"
|
2020-11-16 13:18:14 +00:00
|
|
|
|
|
|
|
"github.com/PuerkitoBio/goquery"
|
2020-09-01 16:53:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func urlize(str string) string {
|
|
|
|
newStr := ""
|
|
|
|
for _, c := range strings.Split(strings.ToLower(str), "") {
|
|
|
|
if c >= "a" && c <= "z" || c >= "A" && c <= "Z" || c >= "0" && c <= "9" {
|
|
|
|
newStr += c
|
|
|
|
} else if c == " " {
|
|
|
|
newStr += "-"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newStr
|
|
|
|
}
|
2020-09-15 15:01:53 +00:00
|
|
|
|
2020-09-19 12:56:31 +00:00
|
|
|
func sortedStrings(s []string) []string {
|
|
|
|
sort.Slice(s, func(i, j int) bool {
|
|
|
|
return strings.ToLower(s[i]) < strings.ToLower(s[j])
|
|
|
|
})
|
|
|
|
return s
|
|
|
|
}
|
2020-10-06 17:07:48 +00:00
|
|
|
|
2020-10-26 16:37:31 +00:00
|
|
|
func generateRandomString(chars int) string {
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
2020-10-06 17:07:48 +00:00
|
|
|
letters := []rune("abcdefghijklmnopqrstuvwxyz")
|
2020-10-26 16:37:31 +00:00
|
|
|
b := make([]rune, chars)
|
2020-10-06 17:07:48 +00:00
|
|
|
for i := range b {
|
|
|
|
b[i] = letters[rand.Intn(len(letters))]
|
|
|
|
}
|
|
|
|
return string(b)
|
|
|
|
}
|
2020-11-01 17:37:21 +00:00
|
|
|
|
2020-11-06 17:45:31 +00:00
|
|
|
func isAllowedHost(r *http.Request, hosts ...string) bool {
|
|
|
|
if r.URL == nil {
|
|
|
|
return false
|
2020-11-01 17:37:21 +00:00
|
|
|
}
|
2020-11-06 17:45:31 +00:00
|
|
|
rh := r.URL.Host
|
|
|
|
switch r.URL.Scheme {
|
|
|
|
case "http":
|
|
|
|
rh = strings.TrimSuffix(rh, ":80")
|
|
|
|
case "https":
|
|
|
|
rh = strings.TrimSuffix(rh, ":443")
|
|
|
|
}
|
|
|
|
for _, host := range hosts {
|
|
|
|
if rh == host {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
2020-11-01 17:37:21 +00:00
|
|
|
}
|
2020-11-16 13:18:14 +00:00
|
|
|
|
|
|
|
func isAbsoluteURL(s string) bool {
|
|
|
|
if !strings.HasPrefix(s, "https://") && !strings.HasPrefix(s, "http://") {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if _, err := url.Parse(s); err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func allLinksFromHTML(r io.Reader, baseURL string) ([]string, error) {
|
|
|
|
doc, err := goquery.NewDocumentFromReader(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
links := []string{}
|
|
|
|
doc.Find("a[href]").Each(func(_ int, item *goquery.Selection) {
|
|
|
|
if href, exists := item.Attr("href"); exists {
|
2020-11-16 17:34:29 +00:00
|
|
|
links = append(links, href)
|
2020-11-16 13:18:14 +00:00
|
|
|
}
|
|
|
|
})
|
2020-11-16 17:34:29 +00:00
|
|
|
links, err = resolveURLReferences(baseURL, links...)
|
|
|
|
return links, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func resolveURLReferences(base string, refs ...string) ([]string, error) {
|
|
|
|
b, err := url.Parse(base)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var urls []string
|
|
|
|
for _, r := range refs {
|
|
|
|
u, err := url.Parse(r)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
urls = append(urls, b.ResolveReference(u).String())
|
|
|
|
}
|
|
|
|
return urls, nil
|
2020-11-16 13:18:14 +00:00
|
|
|
}
|
2020-11-17 16:43:30 +00:00
|
|
|
|
2020-11-17 19:01:02 +00:00
|
|
|
func unescapedPath(p string) string {
|
|
|
|
u, err := url.PathUnescape(p)
|
|
|
|
if err != nil {
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
return u
|
|
|
|
}
|
|
|
|
|
2020-11-17 16:43:30 +00:00
|
|
|
func slashIfEmpty(s string) string {
|
|
|
|
if s == "" {
|
|
|
|
return "/"
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
2020-11-22 08:11:57 +00:00
|
|
|
|
|
|
|
type stringGroup struct {
|
|
|
|
Identifier string
|
|
|
|
Strings []string
|
|
|
|
}
|
|
|
|
|
|
|
|
func groupStrings(toGroup []string) []stringGroup {
|
|
|
|
stringMap := map[string][]string{}
|
|
|
|
for _, s := range toGroup {
|
|
|
|
first := strings.ToUpper(s[:1])
|
|
|
|
stringMap[first] = append(stringMap[first], s)
|
|
|
|
}
|
|
|
|
stringGroups := []stringGroup{}
|
|
|
|
for key, sa := range stringMap {
|
|
|
|
stringGroups = append(stringGroups, stringGroup{
|
|
|
|
Identifier: key,
|
|
|
|
Strings: sortedStrings(sa),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
sort.Slice(stringGroups, func(i, j int) bool {
|
|
|
|
return strings.ToLower(stringGroups[i].Identifier) < strings.ToLower(stringGroups[j].Identifier)
|
|
|
|
})
|
|
|
|
return stringGroups
|
|
|
|
}
|