Skip to content

Commit 59cf34c

Browse files
committed
Get machine_id working on macOS as well
1 parent ccbe5d7 commit 59cf34c

5 files changed

Lines changed: 134 additions & 5 deletions

File tree

tools/cmd/mouse_demo/main.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ import (
1010
"encoding/hex"
1111
"fmt"
1212
"net/url"
13-
"os"
1413
"path/filepath"
1514
"strconv"
1615
"strings"
1716

18-
kitty "github.com/kovidgoyal/kitty"
17+
"github.com/kovidgoyal/kitty"
1918
"github.com/kovidgoyal/kitty/tools/tty"
2019
"github.com/kovidgoyal/kitty/tools/tui/loop"
20+
"github.com/kovidgoyal/kitty/tools/utils"
21+
"github.com/kovidgoyal/kitty/tools/utils/machine_id"
2122
)
2223

2324
var _ = fmt.Print
@@ -41,13 +42,12 @@ func dnd_escape(metadata, payload string) string {
4142
// get_machine_id returns the machine id in the format expected by the DnD
4243
// protocol ("1:" followed by HMAC-SHA256 of /etc/machine-id).
4344
func get_machine_id() string {
44-
data, err := os.ReadFile("/etc/machine-id")
45+
ans, err := machine_id.MachineId()
4546
if err != nil {
4647
return ""
4748
}
48-
data = bytes.TrimRight(data, "\n")
4949
mac := hmac.New(sha256.New, []byte("tty-dnd-protocol-machine-id"))
50-
mac.Write(data)
50+
mac.Write(utils.UnsafeStringToBytes(ans))
5151
return "1:" + hex.EncodeToString(mac.Sum(nil))
5252
}
5353

tools/utils/machine_id/api.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package machine_id
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
)
7+
8+
var _ = fmt.Print
9+
10+
var MachineId = sync.OnceValues(read_machine_id)

tools/utils/machine_id/api_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package machine_id
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
var _ = fmt.Print
9+
10+
func TestMachineId(t *testing.T) {
11+
_, err := MachineId()
12+
if err != nil {
13+
t.Fatal(err)
14+
}
15+
}

tools/utils/machine_id/darwin.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//go:build darwin
2+
3+
package machine_id
4+
5+
import (
6+
"fmt"
7+
"strings"
8+
9+
"github.com/ebitengine/purego"
10+
)
11+
12+
var _ = fmt.Print
13+
14+
func read_machine_id() (string, error) {
15+
const kIOMainPortDefault uint32 = 0
16+
const kCFStringEncodingUTF8 uint32 = 0x08000100
17+
18+
// 1. Load System Frameworks
19+
iokit, err := purego.Dlopen("/System/Library/Frameworks/IOKit.framework/IOKit", purego.RTLD_NOW)
20+
if err != nil {
21+
return "", err
22+
}
23+
defer purego.Dlclose(iokit)
24+
corefoundation, err := purego.Dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", purego.RTLD_NOW)
25+
if err != nil {
26+
return "", err
27+
}
28+
defer purego.Dlclose(corefoundation)
29+
30+
// 2. Register CoreFoundation Functions
31+
var cfStringCreateWithCString func(uintptr, *byte, uint32) uintptr
32+
purego.RegisterLibFunc(&cfStringCreateWithCString, corefoundation, "CFStringCreateWithCString")
33+
34+
var cfStringGetCString func(uintptr, *byte, int64, uint32) bool
35+
purego.RegisterLibFunc(&cfStringGetCString, corefoundation, "CFStringGetCString")
36+
37+
var cfRelease func(uintptr)
38+
purego.RegisterLibFunc(&cfRelease, corefoundation, "CFRelease")
39+
40+
// 3. Register IOKit Functions
41+
var ioServiceMatching func(*byte) uintptr
42+
purego.RegisterLibFunc(&ioServiceMatching, iokit, "IOServiceMatching")
43+
44+
var ioServiceGetMatchingService func(uint32, uintptr) uint32
45+
purego.RegisterLibFunc(&ioServiceGetMatchingService, iokit, "IOServiceGetMatchingService")
46+
47+
var ioRegistryEntryCreateCFProperty func(uint32, uintptr, uintptr, uint32) uintptr
48+
purego.RegisterLibFunc(&ioRegistryEntryCreateCFProperty, iokit, "IORegistryEntryCreateCFProperty")
49+
50+
var ioObjectRelease func(uint32)
51+
purego.RegisterLibFunc(&ioObjectRelease, iokit, "IOObjectRelease")
52+
53+
// 4. Retrieve the UUID
54+
// Convert Go string to CFStringRef for the property key
55+
keyName := "IOPlatformUUID\x00"
56+
cfKey := cfStringCreateWithCString(0, &[]byte(keyName)[0], kCFStringEncodingUTF8)
57+
defer cfRelease(cfKey)
58+
59+
// Look up the IOPlatformExpertDevice service
60+
className := "IOPlatformExpertDevice\x00"
61+
matchingDict := ioServiceMatching(&[]byte(className)[0])
62+
service := ioServiceGetMatchingService(kIOMainPortDefault, matchingDict)
63+
if service == 0 {
64+
return "", fmt.Errorf("failed to find IOPlatformExpertDevice service")
65+
}
66+
defer ioObjectRelease(service)
67+
68+
// Get the property from the registry
69+
cfValue := ioRegistryEntryCreateCFProperty(service, cfKey, 0, 0)
70+
if cfValue == 0 {
71+
return "", fmt.Errorf("failed to find IOPlatformUUID property")
72+
}
73+
defer cfRelease(cfValue)
74+
75+
// Convert the resulting CFString back to a Go string
76+
buf := make([]byte, 128)
77+
if cfStringGetCString(cfValue, &buf[0], 128, kCFStringEncodingUTF8) {
78+
return strings.TrimRight(string(buf), "\x00"), nil
79+
}
80+
return "", fmt.Errorf("failed to extract string from CFProperty")
81+
}

tools/utils/machine_id/unix.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//go:build !darwin
2+
3+
package machine_id
4+
5+
import (
6+
"fmt"
7+
"os"
8+
"strings"
9+
"unicode"
10+
11+
"github.com/kovidgoyal/kitty/tools/utils"
12+
)
13+
14+
var _ = fmt.Print
15+
16+
func read_machine_id() (string, error) {
17+
if data, err := os.ReadFile("/etc/machine-id"); err == nil {
18+
ans := utils.UnsafeBytesToString(data)
19+
return strings.TrimRightFunc(ans, unicode.IsSpace), nil
20+
} else {
21+
return "", err
22+
}
23+
}

0 commit comments

Comments
 (0)