118 lines
2.4 KiB
Go
118 lines
2.4 KiB
Go
package utilities
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/supabase/auth/internal/conf"
|
|
)
|
|
|
|
// GetIPAddress returns the real IP address of the HTTP request. It parses the
|
|
// X-Forwarded-For header.
|
|
func GetIPAddress(r *http.Request) string {
|
|
if r.Header != nil {
|
|
xForwardedFor := r.Header.Get("X-Forwarded-For")
|
|
if xForwardedFor != "" {
|
|
ips := strings.Split(xForwardedFor, ",")
|
|
for i := range ips {
|
|
ips[i] = strings.TrimSpace(ips[i])
|
|
}
|
|
|
|
for _, ip := range ips {
|
|
if ip != "" {
|
|
parsed := net.ParseIP(ip)
|
|
if parsed == nil {
|
|
continue
|
|
}
|
|
|
|
return parsed.String()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ipPort := r.RemoteAddr
|
|
ip, _, err := net.SplitHostPort(ipPort)
|
|
if err != nil {
|
|
return ipPort
|
|
}
|
|
|
|
return ip
|
|
}
|
|
|
|
// GetBodyBytes reads the whole request body properly into a byte array.
|
|
func GetBodyBytes(req *http.Request) ([]byte, error) {
|
|
if req.Body == nil || req.Body == http.NoBody {
|
|
return nil, nil
|
|
}
|
|
|
|
originalBody := req.Body
|
|
defer SafeClose(originalBody)
|
|
|
|
buf, err := io.ReadAll(originalBody)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
req.Body = io.NopCloser(bytes.NewReader(buf))
|
|
|
|
return buf, nil
|
|
}
|
|
|
|
func GetReferrer(r *http.Request, config *conf.GlobalConfiguration) string {
|
|
// try get redirect url from query or post data first
|
|
reqref := getRedirectTo(r)
|
|
if IsRedirectURLValid(config, reqref) {
|
|
return reqref
|
|
}
|
|
|
|
// instead try referrer header value
|
|
reqref = r.Referer()
|
|
if IsRedirectURLValid(config, reqref) {
|
|
return reqref
|
|
}
|
|
|
|
return config.SiteURL
|
|
}
|
|
|
|
func IsRedirectURLValid(config *conf.GlobalConfiguration, redirectURL string) bool {
|
|
if redirectURL == "" {
|
|
return false
|
|
}
|
|
|
|
base, berr := url.Parse(config.SiteURL)
|
|
refurl, rerr := url.Parse(redirectURL)
|
|
|
|
// As long as the referrer came from the site, we will redirect back there
|
|
if berr == nil && rerr == nil && base.Hostname() == refurl.Hostname() {
|
|
return true
|
|
}
|
|
|
|
// For case when user came from mobile app or other permitted resource - redirect back
|
|
for _, pattern := range config.URIAllowListMap {
|
|
if pattern.Match(redirectURL) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// getRedirectTo tries extract redirect url from header or from query params
|
|
func getRedirectTo(r *http.Request) (reqref string) {
|
|
reqref = r.Header.Get("redirect_to")
|
|
if reqref != "" {
|
|
return
|
|
}
|
|
|
|
if err := r.ParseForm(); err == nil {
|
|
reqref = r.Form.Get("redirect_to")
|
|
}
|
|
|
|
return
|
|
}
|