feat: unify app and third-party wloc features

This commit is contained in:
xweiba
2026-08-10 13:35:47 +08:00
parent 27af50375d
commit 41dfe7a8ed
36 changed files with 1702 additions and 73 deletions
+15 -1
View File
@@ -55,6 +55,11 @@ func wloccore_validateca(certData, keyData *C.char) C.int {
//export wloccore_startproxy
func wloccore_startproxy(certData, keyData *C.char, lat, lon C.double, enabled C.int, accuracy C.int) C.uintptr_t {
return wloccore_startproxyv2(certData, keyData, lat, lon, enabled, accuracy, 0)
}
//export wloccore_startproxyv2
func wloccore_startproxyv2(certData, keyData *C.char, lat, lon C.double, enabled C.int, accuracy C.int, motionEnabled C.int) C.uintptr_t {
if certData == nil || keyData == nil {
return 0
}
@@ -65,6 +70,7 @@ func wloccore_startproxy(certData, keyData *C.char, lat, lon C.double, enabled C
float64(lon),
enabled != 0,
int(accuracy),
motionEnabled != 0,
)
if err != nil {
logEvent("startproxy failed: " + err.Error())
@@ -106,13 +112,21 @@ func proxyForHandle(h C.uintptr_t) (server *http.Server, handle cgo.Handle, ok b
//export wloccore_setcoords
func wloccore_setcoords(lat, lon C.double, enabled C.int, accuracy C.int) {
wloccore_setpatchconfig(lat, lon, enabled, accuracy, 0)
}
//export wloccore_setpatchconfig
func wloccore_setpatchconfig(lat, lon C.double, enabled C.int, accuracy C.int, motionEnabled C.int) {
stateMu.Lock()
currentLat = float64(lat)
currentLon = float64(lon)
currentEnabled = enabled != 0
currentAccuracy = int(accuracy)
currentMotionSimulationEnabled = motionEnabled != 0
stateMu.Unlock()
logEvent("setcoords enabled=" + strconv.FormatBool(enabled != 0) + " accuracy=" + strconv.Itoa(int(accuracy)))
logEvent("setpatchconfig enabled=" + strconv.FormatBool(enabled != 0) +
" accuracy=" + strconv.Itoa(int(accuracy)) +
" motion=" + strconv.FormatBool(motionEnabled != 0))
}
//export wloccore_getcoords
+17 -12
View File
@@ -22,13 +22,14 @@ import (
const proxyPort = 8888
var (
stateMu sync.Mutex
currentLat float64
currentLon float64
currentEnabled bool
currentAccuracy int
globalCACert *tls.Certificate
verifyToken string
stateMu sync.Mutex
currentLat float64
currentLon float64
currentEnabled bool
currentAccuracy int
currentMotionSimulationEnabled bool
globalCACert *tls.Certificate
verifyToken string
logMu sync.Mutex
logEntries []string
@@ -94,10 +95,10 @@ func newProxy(cert *tls.Certificate) *goproxy.ProxyHttpServer {
}
if r.URL.Path == "/coords" {
stateMu.Lock()
enabled, lat, lon, accuracy := currentEnabled, currentLat, currentLon, currentAccuracy
enabled, lat, lon, accuracy, motionEnabled := currentEnabled, currentLat, currentLon, currentAccuracy, currentMotionSimulationEnabled
stateMu.Unlock()
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(fmt.Sprintf(`{"enabled":%t,"lat":%.6f,"lon":%.6f,"accuracy":%d}`, enabled, lat, lon, accuracy)))
w.Write([]byte(fmt.Sprintf(`{"enabled":%t,"lat":%.6f,"lon":%.6f,"accuracy":%d,"motionSimulationEnabled":%t}`, enabled, lat, lon, accuracy, motionEnabled)))
return
}
if r.URL.Path == "/proxy.mobileconfig" || r.URL.Path == "/proxy.mobileconfig/" {
@@ -221,7 +222,7 @@ func patchWlocResponse(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Respons
}
stateMu.Lock()
enabled, lat, lon, accuracy := currentEnabled, currentLat, currentLon, currentAccuracy
enabled, lat, lon, accuracy, motionEnabled := currentEnabled, currentLat, currentLon, currentAccuracy, currentMotionSimulationEnabled
stateMu.Unlock()
const maxPatchBodyBytes int64 = 1 << 20
@@ -249,7 +250,10 @@ func patchWlocResponse(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Respons
return resp
}
patched, stats, err := patchResponseBody(body, wlocCoords{Latitude: lat, Longitude: lon, Accuracy: accuracy})
patched, stats, err := patchResponseBody(body, wlocCoords{
Latitude: lat, Longitude: lon, Accuracy: accuracy,
MotionSimulationEnabled: motionEnabled,
})
if err != nil || bytes.Equal(patched, body) {
if err != nil {
logEvent("wloc patch skipped: " + err.Error())
@@ -326,7 +330,7 @@ func randomUint32() uint32 {
return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
}
func startProxy(certPEM, keyPEM []byte, lat, lon float64, enabled bool, accuracy int) (*http.Server, error) {
func startProxy(certPEM, keyPEM []byte, lat, lon float64, enabled bool, accuracy int, motionEnabled bool) (*http.Server, error) {
cert, err := parseCA(certPEM, keyPEM)
if err != nil {
return nil, err
@@ -335,6 +339,7 @@ func startProxy(certPEM, keyPEM []byte, lat, lon float64, enabled bool, accuracy
stateMu.Lock()
globalCACert = cert
currentLat, currentLon, currentEnabled, currentAccuracy = lat, lon, enabled, accuracy
currentMotionSimulationEnabled = motionEnabled
stateMu.Unlock()
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", proxyPort))
+34 -3
View File
@@ -20,11 +20,17 @@ const (
)
type wlocCoords struct {
Latitude float64
Longitude float64
Accuracy int
Latitude float64
Longitude float64
Accuracy int
MotionSimulationEnabled bool
}
const (
motionActivityType = 63
motionActivityConfidence = 467
)
type patchStats struct {
WiFi int
Cell int
@@ -179,6 +185,7 @@ func patchLocation(loc []byte, c wlocCoords) ([]byte, bool, error) {
lon := int64(math.Round(c.Longitude * 1e8))
var out []byte
changed := false
hasMotionType, hasMotionConfidence := false, false
for _, f := range fields {
switch {
case f.num == 1 && f.wireType == wireVarint:
@@ -199,10 +206,34 @@ func patchLocation(loc []byte, c wlocCoords) ([]byte, bool, error) {
changed = true
}
out = append(out, raw...)
case c.MotionSimulationEnabled && f.num == 11 && f.wireType == wireVarint:
hasMotionType = true
raw := append(writeTag(11, wireVarint), writeVarint(motionActivityType)...)
if !bytes.Equal(raw, f.raw) {
changed = true
}
out = append(out, raw...)
case c.MotionSimulationEnabled && f.num == 12 && f.wireType == wireVarint:
hasMotionConfidence = true
raw := append(writeTag(12, wireVarint), writeVarint(motionActivityConfidence)...)
if !bytes.Equal(raw, f.raw) {
changed = true
}
out = append(out, raw...)
default:
out = append(out, f.raw...)
}
}
if c.MotionSimulationEnabled && !hasMotionType {
out = append(out, writeTag(11, wireVarint)...)
out = append(out, writeVarint(motionActivityType)...)
changed = true
}
if c.MotionSimulationEnabled && !hasMotionConfidence {
out = append(out, writeTag(12, wireVarint)...)
out = append(out, writeVarint(motionActivityConfidence)...)
changed = true
}
return out, changed, nil
}
+69
View File
@@ -25,6 +25,15 @@ func testLocation(lat, lon int64, accuracy uint64) []byte {
return out
}
func testLocationWithMotion(lat, lon int64, accuracy, motionType, motionConfidence uint64) []byte {
out := testLocation(lat, lon, accuracy)
out = append(out, writeTag(11, wireVarint)...)
out = append(out, writeVarint(motionType)...)
out = append(out, writeTag(12, wireVarint)...)
out = append(out, writeVarint(motionConfidence)...)
return out
}
func testWifiDevice(loc []byte) []byte {
mac := []byte("aa:bb:cc:dd:ee:ff")
var out []byte
@@ -113,6 +122,66 @@ func TestPatchCellLocation(t *testing.T) {
}
}
func TestMotionSimulationDisabledPreservesFields(t *testing.T) {
original := testLocationWithMotion(100, 200, 25, 7, 88)
patched, changed, err := patchLocation(original, wlocCoords{
Latitude: 31.230416, Longitude: 121.473701, Accuracy: 50,
})
if err != nil {
t.Fatal(err)
}
if !changed {
t.Fatal("coordinates were not patched")
}
fields, err := parseFields(patched)
if err != nil {
t.Fatal(err)
}
for _, field := range fields {
if (field.num == 11 || field.num == 12) && !bytes.Contains(original, field.raw) {
t.Fatalf("motion field %d changed while disabled", field.num)
}
}
}
func TestMotionSimulationEnabledReplacesFields(t *testing.T) {
original := testLocationWithMotion(100, 200, 25, 7, 88)
patched, _, err := patchLocation(original, wlocCoords{
Latitude: 31.230416, Longitude: 121.473701, Accuracy: 50,
MotionSimulationEnabled: true,
})
if err != nil {
t.Fatal(err)
}
if !bytes.Contains(patched, append(writeTag(11, wireVarint), writeVarint(motionActivityType)...)) {
t.Fatal("motion activity type was not replaced")
}
if !bytes.Contains(patched, append(writeTag(12, wireVarint), writeVarint(motionActivityConfidence)...)) {
t.Fatal("motion activity confidence was not replaced")
}
}
func TestMotionSimulationEnabledAddsMissingFields(t *testing.T) {
patched, _, err := patchLocation(testLocation(100, 200, 25), wlocCoords{
Latitude: 31.230416, Longitude: 121.473701, Accuracy: 50,
MotionSimulationEnabled: true,
})
if err != nil {
t.Fatal(err)
}
fields, err := parseFields(patched)
if err != nil {
t.Fatal(err)
}
counts := map[int]int{}
for _, field := range fields {
counts[field.num]++
}
if counts[11] != 1 || counts[12] != 1 {
t.Fatalf("expected one inserted motion field each, got %+v", counts)
}
}
func TestPatchARPCFramePreservesEnvelopeAndSuffix(t *testing.T) {
payload := writeLengthDelimited(2, testWifiDevice(testLocation(100, 200, 25)))
suffix := []byte{0xde, 0xad, 0xbe, 0xef}