Get machine_id working on macOS as well

This commit is contained in:
Kovid Goyal 2026-04-12 12:31:42 +05:30
parent ccbe5d7db3
commit 59cf34ca58
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
5 changed files with 134 additions and 5 deletions

View file

@ -10,14 +10,15 @@ import (
"encoding/hex"
"fmt"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
kitty "github.com/kovidgoyal/kitty"
"github.com/kovidgoyal/kitty"
"github.com/kovidgoyal/kitty/tools/tty"
"github.com/kovidgoyal/kitty/tools/tui/loop"
"github.com/kovidgoyal/kitty/tools/utils"
"github.com/kovidgoyal/kitty/tools/utils/machine_id"
)
var _ = fmt.Print
@ -41,13 +42,12 @@ func dnd_escape(metadata, payload string) string {
// get_machine_id returns the machine id in the format expected by the DnD
// protocol ("1:" followed by HMAC-SHA256 of /etc/machine-id).
func get_machine_id() string {
data, err := os.ReadFile("/etc/machine-id")
ans, err := machine_id.MachineId()
if err != nil {
return ""
}
data = bytes.TrimRight(data, "\n")
mac := hmac.New(sha256.New, []byte("tty-dnd-protocol-machine-id"))
mac.Write(data)
mac.Write(utils.UnsafeStringToBytes(ans))
return "1:" + hex.EncodeToString(mac.Sum(nil))
}

View file

@ -0,0 +1,10 @@
package machine_id
import (
"fmt"
"sync"
)
var _ = fmt.Print
var MachineId = sync.OnceValues(read_machine_id)

View file

@ -0,0 +1,15 @@
package machine_id
import (
"fmt"
"testing"
)
var _ = fmt.Print
func TestMachineId(t *testing.T) {
_, err := MachineId()
if err != nil {
t.Fatal(err)
}
}

View file

@ -0,0 +1,81 @@
//go:build darwin
package machine_id
import (
"fmt"
"strings"
"github.com/ebitengine/purego"
)
var _ = fmt.Print
func read_machine_id() (string, error) {
const kIOMainPortDefault uint32 = 0
const kCFStringEncodingUTF8 uint32 = 0x08000100
// 1. Load System Frameworks
iokit, err := purego.Dlopen("/System/Library/Frameworks/IOKit.framework/IOKit", purego.RTLD_NOW)
if err != nil {
return "", err
}
defer purego.Dlclose(iokit)
corefoundation, err := purego.Dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", purego.RTLD_NOW)
if err != nil {
return "", err
}
defer purego.Dlclose(corefoundation)
// 2. Register CoreFoundation Functions
var cfStringCreateWithCString func(uintptr, *byte, uint32) uintptr
purego.RegisterLibFunc(&cfStringCreateWithCString, corefoundation, "CFStringCreateWithCString")
var cfStringGetCString func(uintptr, *byte, int64, uint32) bool
purego.RegisterLibFunc(&cfStringGetCString, corefoundation, "CFStringGetCString")
var cfRelease func(uintptr)
purego.RegisterLibFunc(&cfRelease, corefoundation, "CFRelease")
// 3. Register IOKit Functions
var ioServiceMatching func(*byte) uintptr
purego.RegisterLibFunc(&ioServiceMatching, iokit, "IOServiceMatching")
var ioServiceGetMatchingService func(uint32, uintptr) uint32
purego.RegisterLibFunc(&ioServiceGetMatchingService, iokit, "IOServiceGetMatchingService")
var ioRegistryEntryCreateCFProperty func(uint32, uintptr, uintptr, uint32) uintptr
purego.RegisterLibFunc(&ioRegistryEntryCreateCFProperty, iokit, "IORegistryEntryCreateCFProperty")
var ioObjectRelease func(uint32)
purego.RegisterLibFunc(&ioObjectRelease, iokit, "IOObjectRelease")
// 4. Retrieve the UUID
// Convert Go string to CFStringRef for the property key
keyName := "IOPlatformUUID\x00"
cfKey := cfStringCreateWithCString(0, &[]byte(keyName)[0], kCFStringEncodingUTF8)
defer cfRelease(cfKey)
// Look up the IOPlatformExpertDevice service
className := "IOPlatformExpertDevice\x00"
matchingDict := ioServiceMatching(&[]byte(className)[0])
service := ioServiceGetMatchingService(kIOMainPortDefault, matchingDict)
if service == 0 {
return "", fmt.Errorf("failed to find IOPlatformExpertDevice service")
}
defer ioObjectRelease(service)
// Get the property from the registry
cfValue := ioRegistryEntryCreateCFProperty(service, cfKey, 0, 0)
if cfValue == 0 {
return "", fmt.Errorf("failed to find IOPlatformUUID property")
}
defer cfRelease(cfValue)
// Convert the resulting CFString back to a Go string
buf := make([]byte, 128)
if cfStringGetCString(cfValue, &buf[0], 128, kCFStringEncodingUTF8) {
return strings.TrimRight(string(buf), "\x00"), nil
}
return "", fmt.Errorf("failed to extract string from CFProperty")
}

View file

@ -0,0 +1,23 @@
//go:build !darwin
package machine_id
import (
"fmt"
"os"
"strings"
"unicode"
"github.com/kovidgoyal/kitty/tools/utils"
)
var _ = fmt.Print
func read_machine_id() (string, error) {
if data, err := os.ReadFile("/etc/machine-id"); err == nil {
ans := utils.UnsafeBytesToString(data)
return strings.TrimRightFunc(ans, unicode.IsSpace), nil
} else {
return "", err
}
}