2022-07-05 01:32:10 +00:00
|
|
|
package utils
|
|
|
|
|
|
|
|
import (
|
2022-08-07 11:13:56 +00:00
|
|
|
"fmt"
|
2022-07-05 01:32:10 +00:00
|
|
|
"net/url"
|
|
|
|
"path"
|
2022-08-07 11:13:56 +00:00
|
|
|
"strings"
|
2022-07-05 01:32:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// URLPathFullClean returns a URL path with the query parameters appended (full path) with the path portion parsed
|
|
|
|
// through path.Clean given a *url.URL.
|
2022-07-18 04:59:13 +00:00
|
|
|
func URLPathFullClean(u *url.URL) (output string) {
|
|
|
|
lengthPath := len(u.Path)
|
|
|
|
lengthQuery := len(u.RawQuery)
|
|
|
|
appendForwardSlash := lengthPath > 1 && u.Path[lengthPath-1] == '/'
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case lengthPath == 1 && lengthQuery == 0:
|
|
|
|
return u.Path
|
|
|
|
case lengthPath == 1:
|
2022-07-05 01:32:10 +00:00
|
|
|
return path.Clean(u.Path) + "?" + u.RawQuery
|
2022-07-18 04:59:13 +00:00
|
|
|
case lengthQuery != 0 && appendForwardSlash:
|
|
|
|
return path.Clean(u.Path) + "/?" + u.RawQuery
|
|
|
|
case lengthQuery != 0:
|
|
|
|
return path.Clean(u.Path) + "?" + u.RawQuery
|
|
|
|
case appendForwardSlash:
|
|
|
|
return path.Clean(u.Path) + "/"
|
|
|
|
default:
|
|
|
|
return path.Clean(u.Path)
|
2022-07-05 01:32:10 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-07 11:13:56 +00:00
|
|
|
|
2022-09-03 01:51:02 +00:00
|
|
|
// IsURIStringSafeRedirection determines whether the URI is safe to be redirected to.
|
|
|
|
func IsURIStringSafeRedirection(uri, protectedDomain string) (safe bool, err error) {
|
|
|
|
var parsedURI *url.URL
|
|
|
|
|
|
|
|
if parsedURI, err = url.ParseRequestURI(uri); err != nil {
|
|
|
|
return false, fmt.Errorf("failed to parse URI '%s': %w", uri, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return parsedURI != nil && IsURISafeRedirection(parsedURI, protectedDomain), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsURISafeRedirection returns true if the URI passes the IsURISecure and HasURIDomainSuffix, i.e. if the scheme is
|
|
|
|
// secure and the given URI has a hostname that is either exactly equal to the given domain or if it has a suffix of the
|
|
|
|
// domain prefixed with a period.
|
|
|
|
func IsURISafeRedirection(uri *url.URL, domain string) bool {
|
|
|
|
return IsURISecure(uri) && HasURIDomainSuffix(uri, domain)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsURISecure returns true if the URI has a secure schemes (https or wss).
|
|
|
|
func IsURISecure(uri *url.URL) bool {
|
|
|
|
switch uri.Scheme {
|
|
|
|
case https, wss:
|
|
|
|
return true
|
|
|
|
default:
|
2022-08-07 11:13:56 +00:00
|
|
|
return false
|
|
|
|
}
|
2022-09-03 01:51:02 +00:00
|
|
|
}
|
2022-08-07 11:13:56 +00:00
|
|
|
|
2022-09-03 01:51:02 +00:00
|
|
|
// HasURIDomainSuffix returns true if the URI hostname is equal to the domain or if it has a suffix of the domain
|
|
|
|
// prefixed with a period.
|
|
|
|
func HasURIDomainSuffix(uri *url.URL, domain string) bool {
|
2022-08-07 11:13:56 +00:00
|
|
|
if uri.Hostname() == domain {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasSuffix(uri.Hostname(), period+domain) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|