Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
73 lines
1.6 KiB
Go
73 lines
1.6 KiB
Go
// Copyright © 2023 Ory Corp
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package httpx
|
|
|
|
import (
|
|
"net"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type GeoLocation struct {
|
|
City string
|
|
Region string
|
|
Country string
|
|
Latitude *float64
|
|
Longitude *float64
|
|
}
|
|
|
|
func GetClientIPAddressesWithoutInternalIPs(ipAddresses []string) (string, error) {
|
|
var res string
|
|
|
|
for i := len(ipAddresses) - 1; i >= 0; i-- {
|
|
ip := strings.TrimSpace(ipAddresses[i])
|
|
|
|
if !net.ParseIP(ip).IsPrivate() {
|
|
res = ip
|
|
break
|
|
}
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func ClientIP(r *http.Request) string {
|
|
if trueClientIP := r.Header.Get("True-Client-IP"); trueClientIP != "" {
|
|
return trueClientIP
|
|
} else if cfConnectingIP := r.Header.Get("Cf-Connecting-IP"); cfConnectingIP != "" {
|
|
return cfConnectingIP
|
|
} else if realClientIP := r.Header.Get("X-Real-IP"); realClientIP != "" {
|
|
return realClientIP
|
|
} else if forwardedIP := r.Header.Get("X-Forwarded-For"); forwardedIP != "" {
|
|
ip, _ := GetClientIPAddressesWithoutInternalIPs(strings.Split(forwardedIP, ","))
|
|
return ip
|
|
} else {
|
|
return r.RemoteAddr
|
|
}
|
|
}
|
|
|
|
func parseFloatHeaderValue(headerValue string) *float64 {
|
|
if headerValue == "" {
|
|
return nil
|
|
}
|
|
|
|
val, err := strconv.ParseFloat(headerValue, 64)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return &val
|
|
}
|
|
|
|
func ClientGeoLocation(r *http.Request) *GeoLocation {
|
|
return &GeoLocation{
|
|
City: r.Header.Get("Cf-Ipcity"),
|
|
Region: r.Header.Get("Cf-Region-Code"),
|
|
Country: r.Header.Get("Cf-Ipcountry"),
|
|
Longitude: parseFloatHeaderValue(r.Header.Get("Cf-Iplongitude")),
|
|
Latitude: parseFloatHeaderValue(r.Header.Get("Cf-Iplatitude")),
|
|
}
|
|
}
|