Skip to content

Commit 1789061

Browse files
committed
feature: implement scan
Signed-off-by: deadprogram <[email protected]>
1 parent 36006cb commit 1789061

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

go.mod

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
11
module github.com/hybridgroup/go-haystack
22

33
go 1.23.0
4+
5+
require tinygo.org/x/bluetooth v0.10.1-0.20250110080820-c6dfccb1a90b
6+
7+
require (
8+
github.com/go-ole/go-ole v1.2.6 // indirect
9+
github.com/godbus/dbus/v5 v5.1.0 // indirect
10+
github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b // indirect
11+
github.com/sirupsen/logrus v1.9.3 // indirect
12+
github.com/soypat/cyw43439 v0.0.0-20241116210509-ae1ce0e084c5 // indirect
13+
github.com/soypat/seqs v0.0.0-20240527012110-1201bab640ef // indirect
14+
github.com/tinygo-org/cbgo v0.0.4 // indirect
15+
github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899 // indirect
16+
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 // indirect
17+
golang.org/x/sys v0.11.0 // indirect
18+
)

go.sum

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
5+
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
6+
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
7+
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
8+
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
9+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
10+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
11+
github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b h1:du3zG5fd8snsFN6RBoLA7fpaYV9ZQIsyH9snlk2Zvik=
12+
github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b/go.mod h1:CIltaIm7qaANUIvzr0Vmz71lmQMAIbGJ7cvgzX7FMfA=
13+
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
14+
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
15+
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
16+
github.com/soypat/cyw43439 v0.0.0-20241116210509-ae1ce0e084c5 h1:arwJFX1x5zq+wUp5ADGgudhMQEXKNMQOmTh+yYgkwzw=
17+
github.com/soypat/cyw43439 v0.0.0-20241116210509-ae1ce0e084c5/go.mod h1:1Otjk6PRhfzfcVHeWMEeku/VntFqWghUwuSQyivb2vE=
18+
github.com/soypat/seqs v0.0.0-20240527012110-1201bab640ef h1:phH95I9wANjTYw6bSYLZDQfNvao+HqYDom8owbNa0P4=
19+
github.com/soypat/seqs v0.0.0-20240527012110-1201bab640ef/go.mod h1:oCVCNGCHMKoBj97Zp9znLbQ1nHxpkmOY9X+UAGzOxc8=
20+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
21+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
22+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
23+
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
24+
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
25+
github.com/tinygo-org/cbgo v0.0.4 h1:3D76CRYbH03Rudi8sEgs/YO0x3JIMdyq8jlQtk/44fU=
26+
github.com/tinygo-org/cbgo v0.0.4/go.mod h1:7+HgWIHd4nbAz0ESjGlJ1/v9LDU1Ox8MGzP9mah/fLk=
27+
github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899 h1:/DyaXDEWMqoVUVEJVJIlNk1bXTbFs8s3Q4GdPInSKTQ=
28+
github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899/go.mod h1:LU7Dw00NJ+N86QkeTGjMLNkYcEYMor6wTDpTCu0EaH8=
29+
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 h1:/yRP+0AN7mf5DkD3BAI6TOFnd51gEoDEb8o35jIFtgw=
30+
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
31+
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
32+
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
33+
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
34+
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
35+
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
36+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
37+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
38+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
39+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
40+
tinygo.org/x/bluetooth v0.10.1-0.20250110080820-c6dfccb1a90b h1:BVFpFhNd0umlK744qtzCfe4W7Dp20Tj2Eb+FVCpggCE=
41+
tinygo.org/x/bluetooth v0.10.1-0.20250110080820-c6dfccb1a90b/go.mod h1:XLRopLvxWmIbofpZSXc7BGGCpgFOV5lrZ1i/DQN0BCw=

main.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func main() {
1616

1717
args := flag.Args()
1818
if len(args) < 1 {
19-
fmt.Println("either 'keys' or 'flash' subcommand is required.", len(args))
19+
fmt.Println("either 'keys' 'flash' or 'scan' subcommand is required.", len(args))
2020
return
2121
}
2222

@@ -37,6 +37,10 @@ func main() {
3737
if err := flashDevice(args[1], args[2], verboseFlag); err != nil {
3838
fmt.Println("failed to flash device:", err)
3939
}
40+
case "scan":
41+
if err := scanDevices(verboseFlag); err != nil {
42+
fmt.Println("failed to scan devices:", err)
43+
}
4044
default:
4145
fmt.Println("either 'keys' or 'flash' subcommand is required.")
4246
return

scan.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package main
2+
3+
import (
4+
"encoding/hex"
5+
6+
"errors"
7+
8+
"tinygo.org/x/bluetooth"
9+
)
10+
11+
const (
12+
// Apple, Inc.
13+
appleCompanyID = 0x004C
14+
15+
// Offline Finding type
16+
findMyPayloadType = 0x12
17+
18+
// Length of the payload
19+
findMyPayloadLength = 0x19
20+
21+
// Hint byte
22+
findMyHint = 0x00
23+
)
24+
25+
func scanDevices(verboseFlag *bool) error {
26+
bluetooth.DefaultAdapter.Enable()
27+
28+
return bluetooth.DefaultAdapter.Scan(func(adapter *bluetooth.Adapter, device bluetooth.ScanResult) {
29+
if *verboseFlag {
30+
println("found device:", device.Address.String(), device.RSSI, device.LocalName())
31+
}
32+
33+
if device.ManufacturerData() != nil && device.ManufacturerData()[0].CompanyID == appleCompanyID {
34+
status, key, err := parseData(device.Address, device.ManufacturerData()[0].Data)
35+
if err != nil {
36+
println("failed to parse data:", err)
37+
return
38+
}
39+
println(device.Address.String(), device.RSSI, hex.EncodeToString([]byte{status}), hex.EncodeToString(key))
40+
}
41+
})
42+
}
43+
44+
func parseData(address bluetooth.Address, data []byte) (byte, []byte, error) {
45+
if len(data) < 27 {
46+
return 0, nil, errors.New("data is too short")
47+
}
48+
49+
if data[0] != findMyPayloadType {
50+
return 0, nil, errors.New("invalid payload type")
51+
}
52+
53+
if data[1] != findMyPayloadLength {
54+
return 0, nil, errors.New("invalid payload length")
55+
}
56+
57+
if data[26] != findMyHint {
58+
return 0, nil, errors.New("invalid hint")
59+
}
60+
61+
findMyStatus := data[2]
62+
var key [28]byte
63+
copy(key[6:], data[3:25])
64+
65+
// turn address into key bytes
66+
key[0] = address.MAC[5]
67+
key[1] = address.MAC[4]
68+
key[2] = address.MAC[3]
69+
key[3] = address.MAC[2]
70+
key[4] = address.MAC[1]
71+
key[5] = address.MAC[0]
72+
73+
return findMyStatus, key[:], nil
74+
}

0 commit comments

Comments
 (0)