ipn/ipnlocal, etc: require file sharing capability to send/recv files

tailscale/corp#1582

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2021-04-16 10:57:46 -07:00
parent 2f422434aa
commit b993d9802a
8 changed files with 76 additions and 4 deletions

View File

@@ -2215,12 +2215,36 @@ func (b *LocalBackend) OpenFile(name string) (rc io.ReadCloser, size int64, err
return apiSrv.OpenFile(name)
}
// hasCapFileSharing reports whether the current node has the file
// sharing capability enabled.
func (b *LocalBackend) hasCapFileSharing() bool {
b.mu.Lock()
defer b.mu.Unlock()
return b.hasCapFileSharingLocked()
}
func (b *LocalBackend) hasCapFileSharingLocked() bool {
nm := b.netMap
if nm == nil || nm.SelfNode == nil {
return false
}
for _, c := range nm.SelfNode.Capabilities {
if c == tailcfg.CapabilityFileSharing {
return true
}
}
return false
}
// FileTargets lists nodes that the current node can send files to.
func (b *LocalBackend) FileTargets() ([]*apitype.FileTarget, error) {
var ret []*apitype.FileTarget
b.mu.Lock()
defer b.mu.Unlock()
if !b.hasCapFileSharingLocked() {
return nil, errors.New("file sharing not enabled by Tailscale admin")
}
nm := b.netMap
if b.state != ipn.Running || nm == nil {
return nil, errors.New("not connected")

View File

@@ -410,6 +410,10 @@ func (h *peerAPIHandler) put(w http.ResponseWriter, r *http.Request) {
http.Error(w, "not owner", http.StatusForbidden)
return
}
if !h.ps.b.hasCapFileSharing() {
http.Error(w, "file sharing not enabled by Tailscale admin", http.StatusForbidden)
return
}
if r.Method != "PUT" {
http.Error(w, "not method PUT", http.StatusMethodNotAllowed)
return

View File

@@ -88,7 +88,8 @@ type PeerStatus struct {
KeepAlive bool
ExitNode bool // true if this is the currently selected exit node.
PeerAPIURL []string
PeerAPIURL []string
Capabilities []string `json:",omitempty"`
// ShareeNode indicates this node exists in the netmap because
// it's owned by a shared-to user and that node might connect

View File

@@ -9,6 +9,7 @@ import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net"
@@ -299,6 +300,18 @@ func (h *Handler) serveFiles(w http.ResponseWriter, r *http.Request) {
io.Copy(w, rc)
}
func writeErrorJSON(w http.ResponseWriter, err error) {
if err == nil {
err = errors.New("unexpected nil error")
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(500)
type E struct {
Error string `json:"error"`
}
json.NewEncoder(w).Encode(E{err.Error()})
}
func (h *Handler) serveFileTargets(w http.ResponseWriter, r *http.Request) {
if !h.PermitRead {
http.Error(w, "access denied", http.StatusForbidden)
@@ -310,7 +323,7 @@ func (h *Handler) serveFileTargets(w http.ResponseWriter, r *http.Request) {
}
fts, err := h.b.FileTargets()
if err != nil {
http.Error(w, err.Error(), 500)
writeErrorJSON(w, err)
return
}
makeNonNil(&fts)