oc-discovery -> conf
This commit is contained in:
99
daemons/node/location/location.go
Normal file
99
daemons/node/location/location.go
Normal file
@@ -0,0 +1,99 @@
|
||||
// Package location resolves the geographic position of this node via IP
|
||||
// geolocation and applies a privacy-preserving random offset proportional
|
||||
// to the chosen granularity level before publishing the result.
|
||||
package location
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
peer "cloud.o-forge.io/core/oc-lib/models/peer"
|
||||
)
|
||||
|
||||
// fuzzRadius returns the maximum random offset (in degrees) for each axis
|
||||
// given a granularity level.
|
||||
//
|
||||
// 0 → no location
|
||||
// 1 → continent ±15° lat / ±20° lng
|
||||
// 2 → country ±3° lat / ±4° lng (default)
|
||||
// 3 → region ±0.5° lat / ±0.7° lng
|
||||
// 4 → city ±0.05° lat / ±0.07° lng
|
||||
func fuzzRadius(granularity int) (latR, lngR float64) {
|
||||
switch granularity {
|
||||
case 1:
|
||||
return 15.0, 20.0
|
||||
case 2:
|
||||
return 3.0, 4.0
|
||||
case 3:
|
||||
return 0.5, 0.7
|
||||
case 4:
|
||||
return 0.05, 0.07
|
||||
default:
|
||||
return 3.0, 4.0
|
||||
}
|
||||
}
|
||||
|
||||
// clamp keeps a value inside [min, max].
|
||||
func clamp(v, min, max float64) float64 {
|
||||
if v < min {
|
||||
return min
|
||||
}
|
||||
if v > max {
|
||||
return max
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// ipAPIResponse is the subset of fields returned by ip-api.com/json.
|
||||
type ipAPIResponse struct {
|
||||
Status string `json:"status"`
|
||||
Lat float64 `json:"lat"`
|
||||
Lon float64 `json:"lon"`
|
||||
Country string `json:"country"`
|
||||
Region string `json:"regionName"`
|
||||
City string `json:"city"`
|
||||
}
|
||||
|
||||
// Geolocate resolves the current public IP location via ip-api.com (free,
|
||||
// no key required for non-commercial use), then fuzzes the result according
|
||||
// to granularity.
|
||||
//
|
||||
// Returns nil if granularity == 0 (opt-out) or if the lookup fails.
|
||||
func Geolocate(granularity int) *peer.PeerLocation {
|
||||
if granularity == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
resp, err := client.Get("http://ip-api.com/json?fields=status,lat,lon,country,regionName,city")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result ipAPIResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil || result.Status != "success" {
|
||||
return nil
|
||||
}
|
||||
|
||||
latR, lngR := fuzzRadius(granularity)
|
||||
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
fuzzedLat := result.Lat + (rng.Float64()*2-1)*latR
|
||||
fuzzedLng := result.Lon + (rng.Float64()*2-1)*lngR
|
||||
|
||||
fuzzedLat = clamp(fuzzedLat, -85.0, 85.0)
|
||||
fuzzedLng = clamp(fuzzedLng, -180.0, 180.0)
|
||||
|
||||
fmt.Printf("[location] granularity=%d raw=(%.4f,%.4f) fuzzed=(%.4f,%.4f)\n",
|
||||
granularity, result.Lat, result.Lon, fuzzedLat, fuzzedLng)
|
||||
|
||||
return &peer.PeerLocation{
|
||||
Latitude: fuzzedLat,
|
||||
Longitude: fuzzedLng,
|
||||
Granularity: granularity,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user