mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-31 00:01:40 +01:00
On Windows arm64 we are going to need to ship two different GUI builds; one for Win10 (GOARCH=386) and one for Win11 (GOARCH=amd64, tags += winui). Due to quirks in MSI packaging, they cannot both share the same filename. This requires some fixes in places where we have hardcoded "tailscale-ipn" as the GUI filename. We also do some cleanup in clientupdate to ensure that autoupdates will continue to work correctly with the temporary "-winui" package variant. Fixes #17480 Updates https://github.com/tailscale/corp/issues/29940 Signed-off-by: Aaron Klotz <aaron@tailscale.com>
119 lines
3.1 KiB
Go
119 lines
3.1 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// Package osshare provides utilities for enabling/disabling Taildrop file
|
|
// sharing on Windows.
|
|
package osshare
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
|
|
"golang.org/x/sys/windows/registry"
|
|
"tailscale.com/types/lazy"
|
|
"tailscale.com/types/logger"
|
|
"tailscale.com/util/winutil"
|
|
)
|
|
|
|
const (
|
|
sendFileShellKey = `*\shell\tailscale`
|
|
)
|
|
|
|
var ipnExePath lazy.SyncValue[string] // absolute path of the GUI executable
|
|
|
|
func getIpnExePath(logf logger.Logf) string {
|
|
exe, err := winutil.GUIPathFromReg()
|
|
if err == nil {
|
|
return exe
|
|
}
|
|
|
|
return findGUIInSameDirAsThisExe(logf)
|
|
}
|
|
|
|
func findGUIInSameDirAsThisExe(logf logger.Logf) string {
|
|
// Find the absolute path of the GUI, assuming that it's in the same
|
|
// directory as this executable (tailscaled.exe).
|
|
p, err := os.Executable()
|
|
if err != nil {
|
|
logf("os.Executable error: %v", err)
|
|
return ""
|
|
}
|
|
if p, err = filepath.EvalSymlinks(p); err != nil {
|
|
logf("filepath.EvalSymlinks error: %v", err)
|
|
return ""
|
|
}
|
|
if p, err = filepath.Abs(p); err != nil {
|
|
logf("filepath.Abs error: %v", err)
|
|
return ""
|
|
}
|
|
d := filepath.Dir(p)
|
|
candidates := []string{"tailscale-ipn.exe"}
|
|
if runtime.GOARCH == "arm64" {
|
|
// This name may be used on Windows 10 ARM64.
|
|
candidates = append(candidates, "tailscale-gui-386.exe")
|
|
}
|
|
for _, c := range candidates {
|
|
testPath := filepath.Join(d, c)
|
|
if _, err := os.Stat(testPath); err == nil {
|
|
return testPath
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// SetFileSharingEnabled adds/removes "Send with Tailscale" from the Windows shell menu.
|
|
func SetFileSharingEnabled(enabled bool, logf logger.Logf) {
|
|
logf = logger.WithPrefix(logf, fmt.Sprintf("SetFileSharingEnabled(%v) error: ", enabled))
|
|
if enabled {
|
|
enableFileSharing(logf)
|
|
} else {
|
|
disableFileSharing(logf)
|
|
}
|
|
}
|
|
|
|
func enableFileSharing(logf logger.Logf) {
|
|
path := ipnExePath.Get(func() string {
|
|
return getIpnExePath(logf)
|
|
})
|
|
if path == "" {
|
|
return
|
|
}
|
|
|
|
k, _, err := registry.CreateKey(registry.CLASSES_ROOT, sendFileShellKey, registry.WRITE)
|
|
if err != nil {
|
|
logf("failed to create HKEY_CLASSES_ROOT\\%s reg key: %v", sendFileShellKey, err)
|
|
return
|
|
}
|
|
defer k.Close()
|
|
if err := k.SetStringValue("", "Send with Tailscale..."); err != nil {
|
|
logf("k.SetStringValue error: %v", err)
|
|
return
|
|
}
|
|
if err := k.SetStringValue("Icon", path+",1"); err != nil {
|
|
logf("k.SetStringValue error: %v", err)
|
|
return
|
|
}
|
|
c, _, err := registry.CreateKey(k, "command", registry.WRITE)
|
|
if err != nil {
|
|
logf("failed to create HKEY_CLASSES_ROOT\\%s\\command reg key: %v", sendFileShellKey, err)
|
|
return
|
|
}
|
|
defer c.Close()
|
|
if err := c.SetStringValue("", "\""+path+"\" /push \"%1\""); err != nil {
|
|
logf("c.SetStringValue error: %v", err)
|
|
}
|
|
}
|
|
|
|
func disableFileSharing(logf logger.Logf) {
|
|
if err := registry.DeleteKey(registry.CLASSES_ROOT, sendFileShellKey+"\\command"); err != nil &&
|
|
err != registry.ErrNotExist {
|
|
logf("registry.DeleteKey error: %v\n", err)
|
|
return
|
|
}
|
|
if err := registry.DeleteKey(registry.CLASSES_ROOT, sendFileShellKey); err != nil && err != registry.ErrNotExist {
|
|
logf("registry.DeleteKey error: %v\n", err)
|
|
}
|
|
}
|