authelia/internal/utils/url.go

60 lines
1.5 KiB
Go

package utils
import (
"fmt"
"net/url"
"path"
"strings"
)
// URLPathFullClean returns a URL path with the query parameters appended (full path) with the path portion parsed
// through path.Clean given a *url.URL.
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:
return path.Clean(u.Path) + "?" + u.RawQuery
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)
}
}
// URLDomainHasSuffix determines whether the uri has a suffix of the domain value.
func URLDomainHasSuffix(uri url.URL, domain string) bool {
if uri.Scheme != https {
return false
}
if uri.Hostname() == domain {
return true
}
if strings.HasSuffix(uri.Hostname(), period+domain) {
return true
}
return false
}
// IsRedirectionURISafe determines whether the URI is safe to be redirected to.
func IsRedirectionURISafe(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 && URLDomainHasSuffix(*parsedURI, protectedDomain), nil
}