mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 08:11:32 +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)
 | |
| 	}
 | |
| }
 |