adding mac support mainly

This commit is contained in:
lwoodard
2026-04-13 08:11:19 -06:00
parent 9c681e482e
commit 0f5a136764
9 changed files with 657 additions and 190 deletions

View File

@@ -7,7 +7,6 @@ import (
"flag"
"fmt"
"image"
"image/color"
"image/draw"
"image/gif"
_ "image/jpeg"
@@ -17,6 +16,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"sync"
"time"
@@ -26,9 +26,17 @@ import (
"github.com/fsnotify/fsnotify"
"github.com/srwiley/oksvg"
"github.com/srwiley/rasterx"
"gopkg.in/yaml.v3"
)
const helperSocket = "/run/streamdeck-go/helper.sock"
// helperSocketPath returns the Unix socket path for the privileged helper.
// /run is the standard location on Linux; /var/run is used on macOS.
func helperSocketPath() string {
if runtime.GOOS == "darwin" {
return "/var/run/streamdeck-go/helper.sock"
}
return "/run/streamdeck-go/helper.sock"
}
func main() {
cfgPath := flag.String("config", defaultConfigPath(), "path to config file")
@@ -467,10 +475,39 @@ func runCommand(cmd string) {
}
}
// runPrivileged sends a named command to the helper daemon over its Unix socket.
// The helper validates the name against its root-owned whitelist and runs it.
// runPrivileged dispatches a named privileged command.
// On macOS: reads the user's local whitelist and runs via osascript (admin auth dialog).
// On Linux: sends to the root helper daemon over its Unix socket.
func runPrivileged(name string) error {
conn, err := net.Dial("unix", helperSocket)
if runtime.GOOS == "darwin" {
return runPrivilegedDarwin(name)
}
return runPrivilegedHelper(name)
}
// runPrivilegedDarwin looks up name in ~/.config/streamdeck-go/privileged.yaml
// and executes it via osascript, which shows the standard macOS admin auth dialog.
func runPrivilegedDarwin(name string) error {
wlPath := darwinWhitelistPath()
commands, err := loadPrivilegedCommands(wlPath)
if err != nil {
return fmt.Errorf("load whitelist %q: %w", wlPath, err)
}
shell, ok := commands[name]
if !ok {
return fmt.Errorf("unknown command %q — add it to %s", name, wlPath)
}
script := fmt.Sprintf(`do shell script %q with administrator privileges`, shell)
out, err := exec.Command("osascript", "-e", script).CombinedOutput()
if err != nil {
return fmt.Errorf("%w: %s", err, out)
}
return nil
}
// runPrivilegedHelper sends a named command to the root helper daemon over its Unix socket.
func runPrivilegedHelper(name string) error {
conn, err := net.Dial("unix", helperSocketPath())
if err != nil {
return fmt.Errorf("helper unavailable (is streamdeck-go-helper.service running?): %w", err)
}
@@ -499,6 +536,32 @@ func runPrivileged(name string) error {
return nil
}
func darwinWhitelistPath() string {
base := os.Getenv("XDG_CONFIG_HOME")
if base == "" {
home, _ := os.UserHomeDir()
base = filepath.Join(home, ".config")
}
return filepath.Join(base, "streamdeck-go", "privileged.yaml")
}
func loadPrivilegedCommands(path string) (map[string]string, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var wl struct {
Commands map[string]string `yaml:"commands"`
}
if err := yaml.Unmarshal(data, &wl); err != nil {
return nil, err
}
if wl.Commands == nil {
return map[string]string{}, nil
}
return wl.Commands, nil
}
func defaultConfigPath() string {
base := os.Getenv("XDG_CONFIG_HOME")
if base == "" {
@@ -548,8 +611,3 @@ keys: {}
`
}
func blank(w, h int) image.Image {
img := image.NewRGBA(image.Rect(0, 0, w, h))
draw.Draw(img, img.Bounds(), &image.Uniform{color.Black}, image.Point{}, draw.Src)
return img
}