Adam Ierymenko 5 years ago
parent
commit
d1b780c7be
4 changed files with 99 additions and 9 deletions
  1. 43 0
      go/cmd/zerotier/cli/addroot.go
  2. 2 2
      go/cmd/zerotier/cli/help.go
  3. 17 0
      go/cmd/zerotier/cli/misc.go
  4. 37 7
      go/pkg/zerotier/api.go

+ 43 - 0
go/cmd/zerotier/cli/addroot.go

@@ -13,6 +13,49 @@
 
 package cli
 
+import (
+	"fmt"
+	"io/ioutil"
+	"net/url"
+	"os"
+	"strings"
+
+	"zerotier/pkg/zerotier"
+)
+
 // AddRoot CLI command
 func AddRoot(basePath, authToken string, args []string) {
+	if len(args) == 0 {
+		Help()
+		os.Exit(0)
+	}
+
+	locData, err := ioutil.ReadFile(args[0])
+	if err != nil {
+		fmt.Printf("ERROR: unable to read locator: %s\n", err.Error())
+		os.Exit(1)
+	}
+	loc, err := zerotier.NewLocatorFromBytes(locData)
+	if err != nil {
+		fmt.Printf("ERROR: invalid locator in file '%s': %s\n", args[0], err.Error())
+		os.Exit(1)
+	}
+
+	var name string
+	if len(args) > 1 {
+		if len(args) > 2 {
+			Help()
+			os.Exit(1)
+		}
+		name = strings.TrimSpace(args[1])
+	}
+
+	var result zerotier.Root
+	apiPost(basePath, authToken, "/root/"+url.PathEscape(name), &zerotier.Root{
+		Name:    name,
+		Locator: loc,
+	}, &result)
+
+	fmt.Println(jsonDump(&result))
+	os.Exit(0)
 }

+ 2 - 2
go/cmd/zerotier/cli/help.go

@@ -40,13 +40,13 @@ Commands:
   service                              Start in system service mode
   status                               Show ZeroTier service status and config
   peers                                Show VL1 peers
-  roots                                Show VL1 root servers
+  roots                                Show configured VL1 root servers
   addroot <locator> [name]             Add a VL1 root
   removeroot <name>                    Remove a VL1 root
   locator <command> [args]             Locator management commands
     new <identity> <address> [...]     Create and sign a locator
     newdnskey                          Create a secure DNS name and secret
-    getdns <key> <locator>             Create secure DNS TXT records
+    getdns <dns key> <locator>         Create secure DNS TXT records
   identity <command> [args]            Identity management commands
     new [c25519|p384]                  Create new identity (including secret)
     getpublic <identity>               Extract only public part of identity

+ 17 - 0
go/cmd/zerotier/cli/misc.go

@@ -38,6 +38,23 @@ func apiGet(basePath, authToken, urlPath string, result interface{}) {
 	}
 }
 
+func apiPost(basePath, authToken, urlPath string, post, result interface{}) {
+	statusCode, err := zerotier.APIPost(basePath, zerotier.APISocketName, authToken, urlPath, post, result)
+	if err != nil {
+		fmt.Printf("FATAL: API response code %d: %s\n", statusCode, err.Error())
+		os.Exit(1)
+		return
+	}
+	if statusCode != http.StatusOK {
+		if statusCode == http.StatusUnauthorized {
+			fmt.Printf("FATAL: API response code %d: unauthorized (authorization token incorrect)\n", statusCode)
+		}
+		fmt.Printf("FATAL: API response code %d\n", statusCode)
+		os.Exit(1)
+		return
+	}
+}
+
 func enabledDisabled(f bool) string {
 	if f {
 		return "ENABLED"

+ 37 - 7
go/pkg/zerotier/api.go

@@ -74,8 +74,11 @@ func APIPost(basePath, socketName, authToken, queryPath string, post, result int
 	if err != nil {
 		return http.StatusTeapot, err
 	}
-	err = json.NewDecoder(resp.Body).Decode(result)
-	return resp.StatusCode, err
+	if result != nil {
+		err = json.NewDecoder(resp.Body).Decode(result)
+		return resp.StatusCode, err
+	}
+	return resp.StatusCode, nil
 }
 
 // APIStatus is the object returned by API status inquiries
@@ -337,7 +340,21 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
 			}
 		}
 
-		if req.Method == http.MethodPost || req.Method == http.MethodPut {
+		if req.Method == http.MethodDelete {
+			if queriedID == 0 {
+				_ = apiSendObj(out, req, http.StatusBadRequest, nil)
+			} else {
+				networks := node.Networks()
+				for _, nw := range networks {
+					if nw.id == queriedID {
+						_ = node.Leave(queriedID)
+						_ = apiSendObj(out, req, http.StatusOK, nw)
+						return
+					}
+				}
+				_ = apiSendObj(out, req, http.StatusNotFound, nil)
+			}
+		} else if req.Method == http.MethodPost || req.Method == http.MethodPut {
 			if queriedID == 0 {
 				_ = apiSendObj(out, req, http.StatusBadRequest, nil)
 			} else {
@@ -377,7 +394,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
 				_ = apiSendObj(out, req, http.StatusNotFound, nil)
 			}
 		} else {
-			out.Header().Set("Allow", "GET, HEAD, PUT, POST")
+			out.Header().Set("Allow", "GET, HEAD, PUT, POST, DELETE")
 			_ = apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
 		}
 	})
@@ -401,11 +418,24 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
 			queriedName = req.URL.Path[6:]
 		}
 
-		if req.Method == http.MethodPost || req.Method == http.MethodPut {
+		if req.Method == http.MethodDelete {
+			if len(queriedName) > 0 {
+				roots := node.Roots()
+				for _, r := range roots {
+					if r.Name == queriedName {
+						node.RemoveRoot(queriedName)
+						_ = apiSendObj(out, req, http.StatusOK, r)
+						return
+					}
+				}
+			}
+			_ = apiSendObj(out, req, http.StatusNotFound, nil)
+		} else if req.Method == http.MethodPost || req.Method == http.MethodPut {
 			var r Root
 			if apiReadObj(out, req, &r) == nil {
-				if r.Name != queriedName && (r.Locator == nil || r.Locator.Identity == nil || r.Locator.Identity.address.String() != queriedName) {
+				if r.Name != queriedName {
 					_ = apiSendObj(out, req, http.StatusBadRequest, nil)
+					return
 				}
 				err := node.SetRoot(r.Name, r.Locator)
 				if err != nil {
@@ -431,7 +461,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
 			}
 			_ = apiSendObj(out, req, http.StatusNotFound, nil)
 		} else {
-			out.Header().Set("Allow", "GET, HEAD, PUT, POST")
+			out.Header().Set("Allow", "GET, HEAD, PUT, POST, DELETE")
 			_ = apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
 		}
 	})