misc.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2025-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. package cli
  14. import (
  15. "bufio"
  16. "encoding/json"
  17. "fmt"
  18. "io/ioutil"
  19. "net/http"
  20. "os"
  21. "strconv"
  22. "strings"
  23. "zerotier/pkg/zerotier"
  24. )
  25. func apiGet(basePath, authToken, urlPath string, result interface{}) int64 {
  26. statusCode, clock, err := zerotier.APIGet(basePath, zerotier.APISocketName, authToken, urlPath, result)
  27. if err != nil {
  28. fmt.Printf("FATAL: API response code %d: %s\n", statusCode, err.Error())
  29. os.Exit(1)
  30. return 0
  31. }
  32. if statusCode != http.StatusOK {
  33. if statusCode == http.StatusUnauthorized {
  34. fmt.Printf("FATAL: API response code %d: unauthorized (authorization token incorrect)\n", statusCode)
  35. }
  36. fmt.Printf("FATAL: API response code %d\n", statusCode)
  37. os.Exit(1)
  38. return 0
  39. }
  40. return clock
  41. }
  42. func apiPost(basePath, authToken, urlPath string, post, result interface{}) int64 {
  43. statusCode, clock, err := zerotier.APIPost(basePath, zerotier.APISocketName, authToken, urlPath, post, result)
  44. if err != nil {
  45. fmt.Printf("FATAL: API response code %d: %s\n", statusCode, err.Error())
  46. os.Exit(1)
  47. return 0
  48. }
  49. if statusCode != http.StatusOK {
  50. if statusCode == http.StatusUnauthorized {
  51. fmt.Printf("FATAL: API response code %d: unauthorized (authorization token incorrect)\n", statusCode)
  52. }
  53. fmt.Printf("FATAL: API response code %d\n", statusCode)
  54. os.Exit(1)
  55. return 0
  56. }
  57. return clock
  58. }
  59. func apiDelete(basePath, authToken, urlPath string, result interface{}) int64 {
  60. statusCode, clock, err := zerotier.APIDelete(basePath, zerotier.APISocketName, authToken, urlPath, result)
  61. if err != nil {
  62. fmt.Printf("FATAL: API response code %d: %s\n", statusCode, err.Error())
  63. os.Exit(1)
  64. return 0
  65. }
  66. if statusCode != http.StatusOK {
  67. if statusCode == http.StatusUnauthorized {
  68. fmt.Printf("FATAL: API response code %d: unauthorized (authorization token incorrect)\n", statusCode)
  69. }
  70. fmt.Printf("FATAL: API response code %d\n", statusCode)
  71. os.Exit(1)
  72. return 0
  73. }
  74. return clock
  75. }
  76. func enabledDisabled(f bool) string {
  77. if f {
  78. return "enabled"
  79. }
  80. return "disabled"
  81. }
  82. func allowedBlocked(f bool) string {
  83. if f {
  84. return "allowed"
  85. }
  86. return "blocked"
  87. }
  88. // isTrueStringPrefixChars matches things like [Tt]rue, [Yy]es, 1, [Ee]nabled, and [Aa]llowed
  89. var isTrueStringPrefixChars = [9]uint8{'t', 'T', 'y', 'Y', '1', 'e', 'E', 'a', 'A'}
  90. func isTrue(s string) bool {
  91. if len(s) > 0 {
  92. f := s[0]
  93. for _, c := range isTrueStringPrefixChars {
  94. if c == f {
  95. return true
  96. }
  97. }
  98. }
  99. return false
  100. }
  101. func jsonDump(obj interface{}) string {
  102. j, _ := json.MarshalIndent(obj, "", "\t")
  103. return string(j)
  104. }
  105. // parseAddressFingerprintOrIdentity parses an argument as an address, fingerprint, or identity.
  106. // If it's an address, only that return variable is filled out. Fingerprints fill out both address and
  107. // fingerprint. Identity fills out all three.
  108. func parseAddressFingerprintOrIdentity(s string) (a zerotier.Address, fp *zerotier.Fingerprint, id *zerotier.Identity) {
  109. var err error
  110. s = strings.TrimSpace(s)
  111. hasColon := strings.ContainsRune(s, ':')
  112. hasDash := strings.ContainsRune(s, '-')
  113. if len(s) == zerotier.AddressStringLength && !hasColon && !hasDash {
  114. a, err = zerotier.NewAddressFromString(s)
  115. if err == nil {
  116. return
  117. }
  118. }
  119. if hasDash {
  120. fp, err = zerotier.NewFingerprintFromString(s)
  121. if err == nil {
  122. a = fp.Address
  123. return
  124. }
  125. }
  126. if hasColon {
  127. id, err = zerotier.NewIdentityFromString(s)
  128. if err == nil {
  129. a = id.Address()
  130. fp = id.Fingerprint()
  131. return
  132. }
  133. }
  134. a = zerotier.Address(0)
  135. return
  136. }
  137. func readIdentity(s string) *zerotier.Identity {
  138. if strings.ContainsRune(s, ':') {
  139. id, _ := zerotier.NewIdentityFromString(s)
  140. if id != nil {
  141. return id
  142. }
  143. }
  144. idData, err := ioutil.ReadFile(s)
  145. if err != nil {
  146. fmt.Printf("FATAL: identity '%s' cannot be parsed as file or literal: %s", s, err.Error())
  147. os.Exit(1)
  148. }
  149. id, err := zerotier.NewIdentityFromString(string(idData))
  150. if err != nil {
  151. fmt.Printf("FATAL: identity '%s' cannot be parsed as file or literal: %s", s, err.Error())
  152. os.Exit(1)
  153. }
  154. return id
  155. }
  156. func readLocator(s string) *zerotier.Locator {
  157. if strings.ContainsRune(s, '@') {
  158. loc, _ := zerotier.NewLocatorFromString(s)
  159. if loc != nil {
  160. return loc
  161. }
  162. }
  163. locData, err := ioutil.ReadFile(s)
  164. if err != nil {
  165. fmt.Printf("FATAL: locator '%s' cannot be parsed as file or literal: %s", s, err.Error())
  166. os.Exit(1)
  167. }
  168. loc, err := zerotier.NewLocatorFromString(string(locData))
  169. if err != nil {
  170. fmt.Printf("FATAL: locator '%s' cannot be parsed as file or literal: %s", s, err.Error())
  171. os.Exit(1)
  172. }
  173. return loc
  174. }
  175. func networkStatusStr(status int) string {
  176. switch status {
  177. case zerotier.NetworkStatusNotFound:
  178. return "not-found"
  179. case zerotier.NetworkStatusAccessDenied:
  180. return "access-denied"
  181. case zerotier.NetworkStatusRequestingConfiguration:
  182. return "updating"
  183. case zerotier.NetworkStatusOK:
  184. return "ok"
  185. }
  186. return "???"
  187. }
  188. func readJSONFile(p string, obj interface{}) error {
  189. b, err := ioutil.ReadFile(p)
  190. if err != nil {
  191. return err
  192. }
  193. return json.Unmarshal(b, obj)
  194. }
  195. func isValidAddress(a string) bool {
  196. if len(a) == zerotier.AddressStringLength {
  197. for _, c := range a {
  198. if !strings.ContainsRune("0123456789abcdefABCDEF", c) {
  199. return false
  200. }
  201. }
  202. return true
  203. }
  204. return false
  205. }
  206. func isValidNetworkID(a string) bool {
  207. if len(a) == zerotier.NetworkIDStringLength {
  208. for _, c := range a {
  209. if !strings.ContainsRune("0123456789abcdefABCDEF", c) {
  210. return false
  211. }
  212. }
  213. return true
  214. }
  215. return false
  216. }
  217. func prompt(str string, dfl string) string {
  218. if len(dfl) > 0 {
  219. fmt.Printf("%s [%s]: ", str, dfl)
  220. text, _ := bufio.NewReader(os.Stdin).ReadString('\n')
  221. text = strings.TrimSpace(text)
  222. if len(text) == 0 {
  223. text = dfl
  224. }
  225. return text
  226. }
  227. fmt.Print(str)
  228. text, _ := bufio.NewReader(os.Stdin).ReadString('\n')
  229. return strings.TrimSpace(text)
  230. }
  231. func promptInt(str string, dfl int64) int64 {
  232. s := prompt(str, "")
  233. if len(s) > 0 {
  234. i, err := strconv.ParseInt(s, 10, 64)
  235. if err == nil {
  236. return i
  237. }
  238. }
  239. return dfl
  240. }
  241. func promptFile(str string) []byte {
  242. s := prompt(str, "")
  243. if len(s) > 0 {
  244. b, err := ioutil.ReadFile(s)
  245. if err == nil {
  246. return b
  247. }
  248. }
  249. return nil
  250. }