diff --git a/cmd/derper/depaware.txt b/cmd/derper/depaware.txt index fb83b65f5..c3243ddbd 100644 --- a/cmd/derper/depaware.txt +++ b/cmd/derper/depaware.txt @@ -114,7 +114,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa 💣 tailscale.com/safesocket from tailscale.com/client/tailscale tailscale.com/syncs from tailscale.com/cmd/derper+ tailscale.com/tailcfg from tailscale.com/client/tailscale+ - tailscale.com/tailfs from tailscale.com/client/tailscale + tailscale.com/tailfs from tailscale.com/client/tailscale+ tailscale.com/tka from tailscale.com/client/tailscale+ W tailscale.com/tsconst from tailscale.com/net/interfaces tailscale.com/tstime from tailscale.com/derp+ diff --git a/ipn/backend.go b/ipn/backend.go index 787f026ff..d900fc41d 100644 --- a/ipn/backend.go +++ b/ipn/backend.go @@ -10,6 +10,7 @@ import ( "tailscale.com/ipn/ipnstate" "tailscale.com/tailcfg" + "tailscale.com/tailfs" "tailscale.com/types/empty" "tailscale.com/types/key" "tailscale.com/types/netmap" @@ -123,11 +124,12 @@ type Notify struct { ClientVersion *tailcfg.ClientVersion `json:",omitempty"` // TailFSShares tracks the full set of current TailFSShares that we're - // publishing as name->path. Some client applications, like the MacOS and + // publishing as name->share. Some client applications, like the MacOS and // Windows clients, will listen for updates to this and handle serving // these shares under the identity of the unprivileged user that is running - // the application. - TailFSShares map[string]string `json:",omitempty"` + // the application. A nil value here means that we're not broadcasting + // shares information, an empty value means that there are no shares. + TailFSShares map[string]*tailfs.Share // type is mirrored in xcode/Shared/IPN.swift } diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 03d8b02d7..5141c67a3 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -68,6 +68,7 @@ import ( "tailscale.com/syncs" "tailscale.com/tailcfg" "tailscale.com/taildrop" + "tailscale.com/tailfs" "tailscale.com/tka" "tailscale.com/tsd" "tailscale.com/tstime" @@ -2286,9 +2287,9 @@ func (b *LocalBackend) WatchNotifications(ctx context.Context, mask ipn.NotifyWa if err != nil { b.logf("unable to notify initial tailfs shares: %v", err) } else { - ini.TailFSShares = make(map[string]string, len(shares)) + ini.TailFSShares = make(map[string]*tailfs.Share, len(shares)) for _, share := range shares { - ini.TailFSShares[share.Name] = share.Path + ini.TailFSShares[share.Name] = share } } } diff --git a/ipn/ipnlocal/tailfs.go b/ipn/ipnlocal/tailfs.go index d06599661..b860b8852 100644 --- a/ipn/ipnlocal/tailfs.go +++ b/ipn/ipnlocal/tailfs.go @@ -7,6 +7,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "os" "regexp" "strings" @@ -108,7 +109,7 @@ func normalizeShareName(name string) (string, error) { return name, nil } -func (b *LocalBackend) tailfsAddShareLocked(share *tailfs.Share) (map[string]string, error) { +func (b *LocalBackend) tailfsAddShareLocked(share *tailfs.Share) (map[string]*tailfs.Share, error) { fs, ok := b.sys.TailFSForRemote.GetOK() if !ok { return nil, errors.New("tailfs not enabled") @@ -129,7 +130,7 @@ func (b *LocalBackend) tailfsAddShareLocked(share *tailfs.Share) (map[string]str } fs.SetShares(shares) - return shareNameMap(shares), nil + return maps.Clone(shares), nil } // TailFSRemoveShare removes the named share. Share names are forced to @@ -154,7 +155,7 @@ func (b *LocalBackend) TailFSRemoveShare(name string) error { return nil } -func (b *LocalBackend) tailfsRemoveShareLocked(name string) (map[string]string, error) { +func (b *LocalBackend) tailfsRemoveShareLocked(name string) (map[string]*tailfs.Share, error) { fs, ok := b.sys.TailFSForRemote.GetOK() if !ok { return nil, errors.New("tailfs not enabled") @@ -179,20 +180,12 @@ func (b *LocalBackend) tailfsRemoveShareLocked(name string) (map[string]string, } fs.SetShares(shares) - return shareNameMap(shares), nil -} - -func shareNameMap(sharesByName map[string]*tailfs.Share) map[string]string { - sharesMap := make(map[string]string, len(sharesByName)) - for _, share := range sharesByName { - sharesMap[share.Name] = share.Path - } - return sharesMap + return maps.Clone(shares), nil } // tailfsNotifyShares notifies IPN bus listeners (e.g. Mac Application process) // about the latest set of shares, supplied as a map of name -> directory. -func (b *LocalBackend) tailfsNotifyShares(shares map[string]string) { +func (b *LocalBackend) tailfsNotifyShares(shares map[string]*tailfs.Share) { b.send(ipn.Notify{TailFSShares: shares}) } @@ -205,7 +198,7 @@ func (b *LocalBackend) tailFSNotifyCurrentSharesLocked() { return } // Do the below on a goroutine to avoid deadlocking on b.mu in b.send(). - go b.tailfsNotifyShares(shareNameMap(shares)) + go b.tailfsNotifyShares(maps.Clone(shares)) } // TailFSGetShares returns the current set of shares from the state store, diff --git a/tailfs/remote.go b/tailfs/remote.go index a60620eb4..dca533994 100644 --- a/tailfs/remote.go +++ b/tailfs/remote.go @@ -21,16 +21,16 @@ func AllowShareAs() bool { // Share configures a folder to be shared through TailFS. type Share struct { // Name is how this share appears on remote nodes. - Name string `json:"name"` + Name string `json:"name,omitempty"` // Path is the path to the directory on this machine that's being shared. - Path string `json:"path"` + Path string `json:"path,omitempty"` // As is the UNIX or Windows username of the local account used for this // share. File read/write permissions are enforced based on this username. // Can be left blank to use the default value of "whoever is running the // Tailscale GUI". - As string `json:"who"` + As string `json:"who,omitempty"` // BookmarkData contains security-scoped bookmark data for the Sandboxed // Mac application. The Sandboxed Mac application gains permission to @@ -38,7 +38,7 @@ type Share struct { // picker. In order to retain access to it across restarts, it needs to // hold on to a security-scoped bookmark. That bookmark is stored here. See // https://developer.apple.com/documentation/security/app_sandbox/accessing_files_from_the_macos_app_sandbox#4144043 - BookmarkData []byte `json:"bookmarkData"` + BookmarkData []byte `json:"bookmarkData,omitempty"` } // FileSystemForRemote is the TailFS filesystem exposed to remote nodes. It