123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- // package for logicing client and server code
- package logic
- import (
- "crypto/rand"
- "encoding/base32"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "log/slog"
- "net"
- "net/http"
- "os"
- "reflect"
- "strings"
- "time"
- "unicode"
- "github.com/blang/semver"
- "github.com/c-robinson/iplib"
- "github.com/gravitl/netmaker/database"
- "github.com/gravitl/netmaker/logger"
- )
- // IsBase64 - checks if a string is in base64 format
- // This is used to validate public keys (make sure they're base64 encoded like all public keys should be).
- func IsBase64(s string) bool {
- _, err := base64.StdEncoding.DecodeString(s)
- return err == nil
- }
- // CheckEndpoint - checks if an endpoint is valid
- func CheckEndpoint(endpoint string) bool {
- endpointarr := strings.Split(endpoint, ":")
- return len(endpointarr) == 2
- }
- // FileExists - checks if local file exists
- func FileExists(f string) bool {
- info, err := os.Stat(f)
- if os.IsNotExist(err) {
- return false
- }
- return !info.IsDir()
- }
- // IsAddressInCIDR - util to see if an address is in a cidr or not
- func IsAddressInCIDR(address net.IP, cidr string) bool {
- var _, currentCIDR, cidrErr = net.ParseCIDR(cidr)
- if cidrErr != nil {
- return false
- }
- return currentCIDR.Contains(address)
- }
- // SetNetworkNodesLastModified - sets the network nodes last modified
- func SetNetworkNodesLastModified(networkName string) error {
- timestamp := time.Now().Unix()
- network, err := GetParentNetwork(networkName)
- if err != nil {
- return err
- }
- network.NodesLastModified = timestamp
- data, err := json.Marshal(&network)
- if err != nil {
- return err
- }
- err = database.Insert(networkName, string(data), database.NETWORKS_TABLE_NAME)
- if err != nil {
- return err
- }
- return nil
- }
- // RandomString - returns a random string in a charset
- func RandomString(length int) string {
- randombytes := make([]byte, length)
- _, err := rand.Read(randombytes)
- if err != nil {
- logger.Log(0, "random string", err.Error())
- return ""
- }
- return base32.StdEncoding.EncodeToString(randombytes)[:length]
- }
- // StringSliceContains - sees if a string slice contains a string element
- func StringSliceContains(slice []string, item string) bool {
- for _, s := range slice {
- if s == item {
- return true
- }
- }
- return false
- }
- func SetVerbosity(logLevel int) {
- var level slog.Level
- switch logLevel {
- case 0:
- level = slog.LevelInfo
- case 1:
- level = slog.LevelError
- case 2:
- level = slog.LevelWarn
- case 3:
- level = slog.LevelDebug
- default:
- level = slog.LevelInfo
- }
- // Create the logger with the chosen level
- handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
- Level: level,
- })
- logger := slog.New(handler)
- slog.SetDefault(logger)
- }
- // NormalizeCIDR - returns the first address of CIDR
- func NormalizeCIDR(address string) (string, error) {
- ip, IPNet, err := net.ParseCIDR(address)
- if err != nil {
- return "", err
- }
- if ip.To4() == nil {
- net6 := iplib.Net6FromStr(IPNet.String())
- IPNet.IP = net6.FirstAddress()
- } else {
- net4 := iplib.Net4FromStr(IPNet.String())
- IPNet.IP = net4.NetworkAddress()
- }
- return IPNet.String(), nil
- }
- // StringDifference - returns the elements in `a` that aren't in `b`.
- func StringDifference(a, b []string) []string {
- mb := make(map[string]struct{}, len(b))
- for _, x := range b {
- mb[x] = struct{}{}
- }
- var diff []string
- for _, x := range a {
- if _, found := mb[x]; !found {
- diff = append(diff, x)
- }
- }
- return diff
- }
- // CheckIfFileExists - checks if file exists or not in the given path
- func CheckIfFileExists(filePath string) bool {
- if _, err := os.Stat(filePath); os.IsNotExist(err) {
- return false
- }
- return true
- }
- // RemoveStringSlice - removes an element at given index i
- // from a given string slice
- func RemoveStringSlice(slice []string, i int) []string {
- return append(slice[:i], slice[i+1:]...)
- }
- // IsSlicesEqual tells whether a and b contain the same elements.
- // A nil argument is equivalent to an empty slice.
- func IsSlicesEqual(a, b []string) bool {
- if len(a) != len(b) {
- return false
- }
- for i, v := range a {
- if v != b[i] {
- return false
- }
- }
- return true
- }
- // VersionLessThan checks if v1 < v2 semantically
- // dev is the latest version
- func VersionLessThan(v1, v2 string) (bool, error) {
- if v1 == "dev" {
- return false, nil
- }
- if v2 == "dev" {
- return true, nil
- }
- semVer1 := strings.TrimFunc(v1, func(r rune) bool {
- return !unicode.IsNumber(r)
- })
- semVer2 := strings.TrimFunc(v2, func(r rune) bool {
- return !unicode.IsNumber(r)
- })
- sv1, err := semver.Parse(semVer1)
- if err != nil {
- return false, fmt.Errorf("failed to parse semver1 (%s): %w", semVer1, err)
- }
- sv2, err := semver.Parse(semVer2)
- if err != nil {
- return false, fmt.Errorf("failed to parse semver2 (%s): %w", semVer2, err)
- }
- return sv1.LT(sv2), nil
- }
- // Compare any two maps with any key and value types
- func CompareMaps[K comparable, V any](a, b map[K]V) bool {
- if len(a) != len(b) {
- return false
- }
- for key, valA := range a {
- valB, ok := b[key]
- if !ok {
- return false
- }
- if !reflect.DeepEqual(valA, valB) {
- return false
- }
- }
- return true
- }
- func UniqueStrings(input []string) []string {
- seen := make(map[string]struct{})
- var result []string
- for _, val := range input {
- if _, ok := seen[val]; !ok {
- seen[val] = struct{}{}
- result = append(result, val)
- }
- }
- return result
- }
- func GetClientIP(r *http.Request) string {
- // Trust X-Forwarded-For first
- if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
- parts := strings.Split(xff, ",")
- return strings.TrimSpace(parts[0])
- }
- if xrip := r.Header.Get("X-Real-IP"); xrip != "" {
- return xrip
- }
- ip, _, err := net.SplitHostPort(r.RemoteAddr)
- if err != nil {
- return r.RemoteAddr
- }
- return ip
- }
|