util.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // package for logicing client and server code
  2. package logic
  3. import (
  4. "crypto/rand"
  5. "encoding/base32"
  6. "encoding/base64"
  7. "encoding/json"
  8. "fmt"
  9. "log/slog"
  10. "net"
  11. "os"
  12. "reflect"
  13. "strings"
  14. "time"
  15. "unicode"
  16. "github.com/blang/semver"
  17. "github.com/c-robinson/iplib"
  18. "github.com/gravitl/netmaker/database"
  19. "github.com/gravitl/netmaker/logger"
  20. )
  21. // IsBase64 - checks if a string is in base64 format
  22. // This is used to validate public keys (make sure they're base64 encoded like all public keys should be).
  23. func IsBase64(s string) bool {
  24. _, err := base64.StdEncoding.DecodeString(s)
  25. return err == nil
  26. }
  27. // CheckEndpoint - checks if an endpoint is valid
  28. func CheckEndpoint(endpoint string) bool {
  29. endpointarr := strings.Split(endpoint, ":")
  30. return len(endpointarr) == 2
  31. }
  32. // FileExists - checks if local file exists
  33. func FileExists(f string) bool {
  34. info, err := os.Stat(f)
  35. if os.IsNotExist(err) {
  36. return false
  37. }
  38. return !info.IsDir()
  39. }
  40. // IsAddressInCIDR - util to see if an address is in a cidr or not
  41. func IsAddressInCIDR(address net.IP, cidr string) bool {
  42. var _, currentCIDR, cidrErr = net.ParseCIDR(cidr)
  43. if cidrErr != nil {
  44. return false
  45. }
  46. return currentCIDR.Contains(address)
  47. }
  48. // SetNetworkNodesLastModified - sets the network nodes last modified
  49. func SetNetworkNodesLastModified(networkName string) error {
  50. timestamp := time.Now().Unix()
  51. network, err := GetParentNetwork(networkName)
  52. if err != nil {
  53. return err
  54. }
  55. network.NodesLastModified = timestamp
  56. data, err := json.Marshal(&network)
  57. if err != nil {
  58. return err
  59. }
  60. err = database.Insert(networkName, string(data), database.NETWORKS_TABLE_NAME)
  61. if err != nil {
  62. return err
  63. }
  64. return nil
  65. }
  66. // RandomString - returns a random string in a charset
  67. func RandomString(length int) string {
  68. randombytes := make([]byte, length)
  69. _, err := rand.Read(randombytes)
  70. if err != nil {
  71. logger.Log(0, "random string", err.Error())
  72. return ""
  73. }
  74. return base32.StdEncoding.EncodeToString(randombytes)[:length]
  75. }
  76. // StringSliceContains - sees if a string slice contains a string element
  77. func StringSliceContains(slice []string, item string) bool {
  78. for _, s := range slice {
  79. if s == item {
  80. return true
  81. }
  82. }
  83. return false
  84. }
  85. func SetVerbosity(logLevel int) {
  86. var level slog.Level
  87. switch logLevel {
  88. case 0:
  89. level = slog.LevelInfo
  90. case 1:
  91. level = slog.LevelError
  92. case 2:
  93. level = slog.LevelWarn
  94. case 3:
  95. level = slog.LevelDebug
  96. default:
  97. level = slog.LevelInfo
  98. }
  99. // Create the logger with the chosen level
  100. handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
  101. Level: level,
  102. })
  103. logger := slog.New(handler)
  104. slog.SetDefault(logger)
  105. }
  106. // NormalizeCIDR - returns the first address of CIDR
  107. func NormalizeCIDR(address string) (string, error) {
  108. ip, IPNet, err := net.ParseCIDR(address)
  109. if err != nil {
  110. return "", err
  111. }
  112. if ip.To4() == nil {
  113. net6 := iplib.Net6FromStr(IPNet.String())
  114. IPNet.IP = net6.FirstAddress()
  115. } else {
  116. net4 := iplib.Net4FromStr(IPNet.String())
  117. IPNet.IP = net4.NetworkAddress()
  118. }
  119. return IPNet.String(), nil
  120. }
  121. // StringDifference - returns the elements in `a` that aren't in `b`.
  122. func StringDifference(a, b []string) []string {
  123. mb := make(map[string]struct{}, len(b))
  124. for _, x := range b {
  125. mb[x] = struct{}{}
  126. }
  127. var diff []string
  128. for _, x := range a {
  129. if _, found := mb[x]; !found {
  130. diff = append(diff, x)
  131. }
  132. }
  133. return diff
  134. }
  135. // CheckIfFileExists - checks if file exists or not in the given path
  136. func CheckIfFileExists(filePath string) bool {
  137. if _, err := os.Stat(filePath); os.IsNotExist(err) {
  138. return false
  139. }
  140. return true
  141. }
  142. // RemoveStringSlice - removes an element at given index i
  143. // from a given string slice
  144. func RemoveStringSlice(slice []string, i int) []string {
  145. return append(slice[:i], slice[i+1:]...)
  146. }
  147. // IsSlicesEqual tells whether a and b contain the same elements.
  148. // A nil argument is equivalent to an empty slice.
  149. func IsSlicesEqual(a, b []string) bool {
  150. if len(a) != len(b) {
  151. return false
  152. }
  153. for i, v := range a {
  154. if v != b[i] {
  155. return false
  156. }
  157. }
  158. return true
  159. }
  160. // VersionLessThan checks if v1 < v2 semantically
  161. // dev is the latest version
  162. func VersionLessThan(v1, v2 string) (bool, error) {
  163. if v1 == "dev" {
  164. return false, nil
  165. }
  166. if v2 == "dev" {
  167. return true, nil
  168. }
  169. semVer1 := strings.TrimFunc(v1, func(r rune) bool {
  170. return !unicode.IsNumber(r)
  171. })
  172. semVer2 := strings.TrimFunc(v2, func(r rune) bool {
  173. return !unicode.IsNumber(r)
  174. })
  175. sv1, err := semver.Parse(semVer1)
  176. if err != nil {
  177. return false, fmt.Errorf("failed to parse semver1 (%s): %w", semVer1, err)
  178. }
  179. sv2, err := semver.Parse(semVer2)
  180. if err != nil {
  181. return false, fmt.Errorf("failed to parse semver2 (%s): %w", semVer2, err)
  182. }
  183. return sv1.LT(sv2), nil
  184. }
  185. // Compare any two maps with any key and value types
  186. func CompareMaps[K comparable, V any](a, b map[K]V) bool {
  187. if len(a) != len(b) {
  188. return false
  189. }
  190. for key, valA := range a {
  191. valB, ok := b[key]
  192. if !ok {
  193. return false
  194. }
  195. if !reflect.DeepEqual(valA, valB) {
  196. return false
  197. }
  198. }
  199. return true
  200. }