misc.go 6.6 KB

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