Kaynağa Gözat

Merge branch 'develop' of https://github.com/gravitl/netmaker into ACC-638

abhishek9686 1 yıl önce
ebeveyn
işleme
fc2fff9f9d

+ 41 - 31
controllers/hosts.go

@@ -81,48 +81,58 @@ func upgradeHost(w http.ResponseWriter, r *http.Request) {
 func getHosts(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	currentHosts := []models.Host{}
-	username := r.Header.Get("user")
-	user, err := logic.GetUser(username)
-	if err != nil {
-		return
-	}
-	userPlatformRole, err := logic.GetRole(user.PlatformRoleID)
-	if err != nil {
-		return
-	}
-	respHostsMap := make(map[string]struct{})
-	if !userPlatformRole.FullAccess {
-		nodes, err := logic.GetAllNodes()
+	var err error
+	if r.Header.Get("ismaster") == "yes" {
+		currentHosts, err = logic.GetAllHosts()
 		if err != nil {
-			logger.Log(0, "error fetching all nodes info: ", err.Error())
+			logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 			return
 		}
-		filteredNodes := logic.GetFilteredNodesByUserAccess(*user, nodes)
-		if len(filteredNodes) > 0 {
-			currentHostsMap, err := logic.GetHostsMap()
+	} else {
+		username := r.Header.Get("user")
+		user, err := logic.GetUser(username)
+		if err != nil {
+			return
+		}
+		userPlatformRole, err := logic.GetRole(user.PlatformRoleID)
+		if err != nil {
+			return
+		}
+		respHostsMap := make(map[string]struct{})
+		if !userPlatformRole.FullAccess {
+			nodes, err := logic.GetAllNodes()
 			if err != nil {
-				logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
+				logger.Log(0, "error fetching all nodes info: ", err.Error())
 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 				return
 			}
-			for _, node := range filteredNodes {
-				if _, ok := respHostsMap[node.HostID.String()]; ok {
-					continue
+			filteredNodes := logic.GetFilteredNodesByUserAccess(*user, nodes)
+			if len(filteredNodes) > 0 {
+				currentHostsMap, err := logic.GetHostsMap()
+				if err != nil {
+					logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
+					logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+					return
 				}
-				if host, ok := currentHostsMap[node.HostID.String()]; ok {
-					currentHosts = append(currentHosts, host)
-					respHostsMap[host.ID.String()] = struct{}{}
+				for _, node := range filteredNodes {
+					if _, ok := respHostsMap[node.HostID.String()]; ok {
+						continue
+					}
+					if host, ok := currentHostsMap[node.HostID.String()]; ok {
+						currentHosts = append(currentHosts, host)
+						respHostsMap[host.ID.String()] = struct{}{}
+					}
 				}
-			}
 
-		}
-	} else {
-		currentHosts, err = logic.GetAllHosts()
-		if err != nil {
-			logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
-			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-			return
+			}
+		} else {
+			currentHosts, err = logic.GetAllHosts()
+			if err != nil {
+				logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error())
+				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+				return
+			}
 		}
 	}
 

+ 9 - 6
controllers/network.go

@@ -58,13 +58,16 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
-	username := r.Header.Get("user")
-	user, err := logic.GetUser(username)
-	if err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-		return
+	if r.Header.Get("ismaster") != "yes" {
+		username := r.Header.Get("user")
+		user, err := logic.GetUser(username)
+		if err != nil {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
+		allnetworks = logic.FilterNetworksByRole(allnetworks, *user)
 	}
-	allnetworks = logic.FilterNetworksByRole(allnetworks, *user)
+
 	logger.Log(2, r.Header.Get("user"), "fetched networks.")
 	logic.SortNetworks(allnetworks[:])
 	w.WriteHeader(http.StatusOK)

+ 58 - 54
controllers/node.go

@@ -268,56 +268,59 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
-	username := r.Header.Get("user")
-	user, err := logic.GetUser(username)
-	if err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-		return
-	}
-	userPlatformRole, err := logic.GetRole(user.PlatformRoleID)
-	if err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-		return
-	}
 	filteredNodes := []models.Node{}
-	if !userPlatformRole.FullAccess {
-		nodesMap := make(map[string]struct{})
-		networkRoles := user.NetworkRoles[models.NetworkID(networkName)]
-		for networkRoleID := range networkRoles {
-			userPermTemplate, err := logic.GetRole(networkRoleID)
-			if err != nil {
-				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-				return
-			}
-			if userPermTemplate.FullAccess {
-				break
-			}
-			if rsrcPerms, ok := userPermTemplate.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok {
-				if _, ok := rsrcPerms[models.AllRemoteAccessGwRsrcID]; ok {
-					for _, node := range nodes {
-						if _, ok := nodesMap[node.ID.String()]; ok {
-							continue
-						}
-						if node.IsIngressGateway {
-							nodesMap[node.ID.String()] = struct{}{}
-							filteredNodes = append(filteredNodes, node)
-						}
-					}
-				} else {
-					for gwID, scope := range rsrcPerms {
-						if _, ok := nodesMap[gwID.String()]; ok {
-							continue
+	if r.Header.Get("ismaster") != "yes" {
+		username := r.Header.Get("user")
+		user, err := logic.GetUser(username)
+		if err != nil {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
+		userPlatformRole, err := logic.GetRole(user.PlatformRoleID)
+		if err != nil {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
+
+		if !userPlatformRole.FullAccess {
+			nodesMap := make(map[string]struct{})
+			networkRoles := user.NetworkRoles[models.NetworkID(networkName)]
+			for networkRoleID := range networkRoles {
+				userPermTemplate, err := logic.GetRole(networkRoleID)
+				if err != nil {
+					logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+					return
+				}
+				if userPermTemplate.FullAccess {
+					break
+				}
+				if rsrcPerms, ok := userPermTemplate.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok {
+					if _, ok := rsrcPerms[models.AllRemoteAccessGwRsrcID]; ok {
+						for _, node := range nodes {
+							if _, ok := nodesMap[node.ID.String()]; ok {
+								continue
+							}
+							if node.IsIngressGateway {
+								nodesMap[node.ID.String()] = struct{}{}
+								filteredNodes = append(filteredNodes, node)
+							}
 						}
-						if scope.Read {
-							gwNode, err := logic.GetNodeByID(gwID.String())
-							if err == nil && gwNode.IsIngressGateway {
-								filteredNodes = append(filteredNodes, gwNode)
+					} else {
+						for gwID, scope := range rsrcPerms {
+							if _, ok := nodesMap[gwID.String()]; ok {
+								continue
+							}
+							if scope.Read {
+								gwNode, err := logic.GetNodeByID(gwID.String())
+								if err == nil && gwNode.IsIngressGateway {
+									filteredNodes = append(filteredNodes, gwNode)
+								}
 							}
 						}
 					}
 				}
-			}
 
+			}
 		}
 	}
 	if len(filteredNodes) > 0 {
@@ -348,18 +351,19 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	username := r.Header.Get("user")
-	user, err := logic.GetUser(username)
-	if err != nil {
-		return
-	}
-	userPlatformRole, err := logic.GetRole(user.PlatformRoleID)
-	if err != nil {
-		return
-	}
-	if !userPlatformRole.FullAccess {
-		nodes = logic.GetFilteredNodesByUserAccess(*user, nodes)
+	if r.Header.Get("ismaster") == "no" {
+		user, err := logic.GetUser(username)
+		if err != nil {
+			return
+		}
+		userPlatformRole, err := logic.GetRole(user.PlatformRoleID)
+		if err != nil {
+			return
+		}
+		if !userPlatformRole.FullAccess {
+			nodes = logic.GetFilteredNodesByUserAccess(*user, nodes)
+		}
 	}
-
 	// return all the nodes in JSON/API format
 	apiNodes := logic.GetAllNodesAPI(nodes[:])
 	logger.Log(3, r.Header.Get("user"), "fetched all nodes they have access to")

+ 328 - 343
controllers/user_test.go

@@ -1,376 +1,361 @@
 package controller
 
-import (
-	"bytes"
-	"io"
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	"github.com/go-jose/go-jose/v3/json"
-	"github.com/gorilla/mux"
-
-	"github.com/stretchr/testify/assert"
-
-	"github.com/gravitl/netmaker/logic"
-	"github.com/gravitl/netmaker/models"
-)
+// TODO: Need Update Tests for New User Mgmt
+// func deleteAllUsers(t *testing.T) {
+// 	t.Helper()
+// 	users, _ := logic.GetUsers()
+// 	for _, user := range users {
+// 		if _, err := logic.DeleteUser(user.UserName); err != nil {
+// 			t.Fatal(err)
+// 		}
+// 	}
+// }
 
-func deleteAllUsers(t *testing.T) {
-	t.Helper()
-	users, _ := logic.GetUsers()
-	for _, user := range users {
-		if _, err := logic.DeleteUser(user.UserName); err != nil {
-			t.Fatal(err)
-		}
-	}
-}
+// func TestGetUserNoHashedPassword(t *testing.T) {
+// 	// prepare existing user base
+// 	user := models.User{UserName: "freddie", Password: "password"}
+// 	haveOnlyOneUser(t, user)
 
-func TestGetUserNoHashedPassword(t *testing.T) {
-	// prepare existing user base
-	user := models.User{UserName: "freddie", Password: "password"}
-	haveOnlyOneUser(t, user)
+// 	// prepare request
+// 	rec, req := prepareUserRequest(t, models.User{}, user.UserName)
 
-	// prepare request
-	rec, req := prepareUserRequest(t, models.User{}, user.UserName)
+// 	// test response
+// 	getUser(rec, req)
+// 	assertUserNameButNoPassword(t, rec.Body, user.UserName)
+// }
 
-	// test response
-	getUser(rec, req)
-	assertUserNameButNoPassword(t, rec.Body, user.UserName)
-}
+// func TestCreateAdminNoHashedPassword(t *testing.T) {
+// 	// prepare existing user base
+// 	deleteAllUsers(t)
 
-func TestCreateAdminNoHashedPassword(t *testing.T) {
-	// prepare existing user base
-	deleteAllUsers(t)
+// 	// prepare request
+// 	user := models.User{UserName: "jonathan", Password: "password"}
+// 	rec, req := prepareUserRequest(t, user, "")
 
-	// prepare request
-	user := models.User{UserName: "jonathan", Password: "password"}
-	rec, req := prepareUserRequest(t, user, "")
+// 	// test response
+// 	createSuperAdmin(rec, req)
+// 	assertUserNameButNoPassword(t, rec.Body, user.UserName)
+// }
 
-	// test response
-	createSuperAdmin(rec, req)
-	assertUserNameButNoPassword(t, rec.Body, user.UserName)
-}
+// func prepareUserRequest(t *testing.T, userForBody models.User, userNameForParam string) (*httptest.ResponseRecorder, *http.Request) {
+// 	bits, err := json.Marshal(userForBody)
+// 	assert.Nil(t, err)
+// 	body := bytes.NewReader(bits)
+// 	rec := httptest.NewRecorder()
+// 	req := httptest.NewRequest("ANY", "https://example.com", body) // only the body matters here
+// 	req = mux.SetURLVars(req, map[string]string{"username": userNameForParam})
+// 	req.Header.Set("user", userForBody.UserName)
+// 	return rec, req
+// }
 
-func prepareUserRequest(t *testing.T, userForBody models.User, userNameForParam string) (*httptest.ResponseRecorder, *http.Request) {
-	bits, err := json.Marshal(userForBody)
-	assert.Nil(t, err)
-	body := bytes.NewReader(bits)
-	rec := httptest.NewRecorder()
-	req := httptest.NewRequest("ANY", "https://example.com", body) // only the body matters here
-	req = mux.SetURLVars(req, map[string]string{"username": userNameForParam})
-	req.Header.Set("user", userForBody.UserName)
-	return rec, req
-}
+// func haveOnlyOneUser(t *testing.T, user models.User) {
+// 	deleteAllUsers(t)
+// 	var err error
+// 	if user.PlatformRoleID == models.SuperAdminRole {
+// 		err = logic.CreateSuperAdmin(&user)
+// 	} else {
+// 		err = logic.CreateUser(&user)
+// 	}
+// 	assert.Nil(t, err)
+// }
 
-func haveOnlyOneUser(t *testing.T, user models.User) {
-	deleteAllUsers(t)
-	var err error
-	if user.PlatformRoleID == models.SuperAdminRole {
-		err = logic.CreateSuperAdmin(&user)
-	} else {
-		err = logic.CreateUser(&user)
-	}
-	assert.Nil(t, err)
-}
+// func assertUserNameButNoPassword(t *testing.T, r io.Reader, userName string) {
+// 	var resp models.User
+// 	err := json.NewDecoder(r).Decode(&resp)
+// 	assert.Nil(t, err)
+// 	assert.Equal(t, userName, resp.UserName)
+// 	assert.Empty(t, resp.Password)
+// }
 
-func assertUserNameButNoPassword(t *testing.T, r io.Reader, userName string) {
-	var resp models.User
-	err := json.NewDecoder(r).Decode(&resp)
-	assert.Nil(t, err)
-	assert.Equal(t, userName, resp.UserName)
-	assert.Empty(t, resp.Password)
-}
+// func TestHasSuperAdmin(t *testing.T) {
+// 	// delete all current users
+// 	users, _ := logic.GetUsers()
+// 	for _, user := range users {
+// 		success, err := logic.DeleteUser(user.UserName)
+// 		assert.Nil(t, err)
+// 		assert.True(t, success)
+// 	}
+// 	t.Run("NoUser", func(t *testing.T) {
+// 		found, err := logic.HasSuperAdmin()
+// 		assert.Nil(t, err)
+// 		assert.False(t, found)
+// 	})
+// 	t.Run("No superadmin user", func(t *testing.T) {
+// 		var user = models.User{UserName: "nosuperadmin", Password: "password"}
+// 		err := logic.CreateUser(&user)
+// 		assert.Nil(t, err)
+// 		found, err := logic.HasSuperAdmin()
+// 		assert.Nil(t, err)
+// 		assert.False(t, found)
+// 	})
+// 	t.Run("superadmin user", func(t *testing.T) {
+// 		var user = models.User{UserName: "superadmin", Password: "password", PlatformRoleID: models.SuperAdminRole}
+// 		err := logic.CreateUser(&user)
+// 		assert.Nil(t, err)
+// 		found, err := logic.HasSuperAdmin()
+// 		assert.Nil(t, err)
+// 		assert.True(t, found)
+// 	})
+// 	t.Run("multiple superadmins", func(t *testing.T) {
+// 		var user = models.User{UserName: "superadmin1", Password: "password", PlatformRoleID: models.SuperAdminRole}
+// 		err := logic.CreateUser(&user)
+// 		assert.Nil(t, err)
+// 		found, err := logic.HasSuperAdmin()
+// 		assert.Nil(t, err)
+// 		assert.True(t, found)
+// 	})
+// }
 
-func TestHasSuperAdmin(t *testing.T) {
-	// delete all current users
-	users, _ := logic.GetUsers()
-	for _, user := range users {
-		success, err := logic.DeleteUser(user.UserName)
-		assert.Nil(t, err)
-		assert.True(t, success)
-	}
-	t.Run("NoUser", func(t *testing.T) {
-		found, err := logic.HasSuperAdmin()
-		assert.Nil(t, err)
-		assert.False(t, found)
-	})
-	t.Run("No superadmin user", func(t *testing.T) {
-		var user = models.User{UserName: "nosuperadmin", Password: "password"}
-		err := logic.CreateUser(&user)
-		assert.Nil(t, err)
-		found, err := logic.HasSuperAdmin()
-		assert.Nil(t, err)
-		assert.False(t, found)
-	})
-	t.Run("superadmin user", func(t *testing.T) {
-		var user = models.User{UserName: "superadmin", Password: "password", PlatformRoleID: models.SuperAdminRole}
-		err := logic.CreateUser(&user)
-		assert.Nil(t, err)
-		found, err := logic.HasSuperAdmin()
-		assert.Nil(t, err)
-		assert.True(t, found)
-	})
-	t.Run("multiple superadmins", func(t *testing.T) {
-		var user = models.User{UserName: "superadmin1", Password: "password", PlatformRoleID: models.SuperAdminRole}
-		err := logic.CreateUser(&user)
-		assert.Nil(t, err)
-		found, err := logic.HasSuperAdmin()
-		assert.Nil(t, err)
-		assert.True(t, found)
-	})
-}
+// func TestCreateUser(t *testing.T) {
+// 	deleteAllUsers(t)
+// 	user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
+// 	t.Run("NoUser", func(t *testing.T) {
+// 		err := logic.CreateUser(&user)
+// 		assert.Nil(t, err)
+// 	})
+// 	t.Run("UserExists", func(t *testing.T) {
+// 		err := logic.CreateUser(&user)
+// 		assert.NotNil(t, err)
+// 		assert.EqualError(t, err, "user exists")
+// 	})
+// }
 
-func TestCreateUser(t *testing.T) {
-	deleteAllUsers(t)
-	user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
-	t.Run("NoUser", func(t *testing.T) {
-		err := logic.CreateUser(&user)
-		assert.Nil(t, err)
-	})
-	t.Run("UserExists", func(t *testing.T) {
-		err := logic.CreateUser(&user)
-		assert.NotNil(t, err)
-		assert.EqualError(t, err, "user exists")
-	})
-}
+// func TestCreateSuperAdmin(t *testing.T) {
+// 	deleteAllUsers(t)
+// 	logic.ClearSuperUserCache()
+// 	var user models.User
+// 	t.Run("NoSuperAdmin", func(t *testing.T) {
+// 		user.UserName = "admin"
+// 		user.Password = "password"
+// 		err := logic.CreateSuperAdmin(&user)
+// 		assert.Nil(t, err)
+// 	})
+// 	t.Run("SuperAdminExists", func(t *testing.T) {
+// 		user.UserName = "admin2"
+// 		user.Password = "password1"
+// 		err := logic.CreateSuperAdmin(&user)
+// 		assert.EqualError(t, err, "superadmin user already exists")
+// 	})
+// }
 
-func TestCreateSuperAdmin(t *testing.T) {
-	deleteAllUsers(t)
-	logic.ClearSuperUserCache()
-	var user models.User
-	t.Run("NoSuperAdmin", func(t *testing.T) {
-		user.UserName = "admin"
-		user.Password = "password"
-		err := logic.CreateSuperAdmin(&user)
-		assert.Nil(t, err)
-	})
-	t.Run("SuperAdminExists", func(t *testing.T) {
-		user.UserName = "admin2"
-		user.Password = "password1"
-		err := logic.CreateSuperAdmin(&user)
-		assert.EqualError(t, err, "superadmin user already exists")
-	})
-}
+// func TestDeleteUser(t *testing.T) {
+// 	deleteAllUsers(t)
+// 	t.Run("NonExistent User", func(t *testing.T) {
+// 		deleted, err := logic.DeleteUser("admin")
+// 		assert.EqualError(t, err, "user does not exist")
+// 		assert.False(t, deleted)
+// 	})
+// 	t.Run("Existing User", func(t *testing.T) {
+// 		user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
+// 		if err := logic.CreateUser(&user); err != nil {
+// 			t.Fatal(err)
+// 		}
+// 		deleted, err := logic.DeleteUser("admin")
+// 		assert.Nil(t, err)
+// 		assert.True(t, deleted)
+// 	})
+// }
 
-func TestDeleteUser(t *testing.T) {
-	deleteAllUsers(t)
-	t.Run("NonExistent User", func(t *testing.T) {
-		deleted, err := logic.DeleteUser("admin")
-		assert.EqualError(t, err, "user does not exist")
-		assert.False(t, deleted)
-	})
-	t.Run("Existing User", func(t *testing.T) {
-		user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
-		if err := logic.CreateUser(&user); err != nil {
-			t.Fatal(err)
-		}
-		deleted, err := logic.DeleteUser("admin")
-		assert.Nil(t, err)
-		assert.True(t, deleted)
-	})
-}
+// func TestValidateUser(t *testing.T) {
+// 	var user models.User
+// 	t.Run("Valid Create", func(t *testing.T) {
+// 		user.UserName = "admin"
+// 		user.Password = "validpass"
+// 		err := logic.ValidateUser(&user)
+// 		assert.Nil(t, err)
+// 	})
+// 	t.Run("Valid Update", func(t *testing.T) {
+// 		user.UserName = "admin"
+// 		user.Password = "password"
+// 		err := logic.ValidateUser(&user)
+// 		assert.Nil(t, err)
+// 	})
+// 	t.Run("Invalid UserName", func(t *testing.T) {
+// 		t.Skip()
+// 		user.UserName = "*invalid"
+// 		err := logic.ValidateUser(&user)
+// 		assert.Error(t, err)
+// 		// assert.Contains(t, err.Error(), "Field validation for 'UserName' failed")
+// 	})
+// 	t.Run("Short UserName", func(t *testing.T) {
+// 		t.Skip()
+// 		user.UserName = "1"
+// 		err := logic.ValidateUser(&user)
+// 		assert.NotNil(t, err)
+// 		// assert.Contains(t, err.Error(), "Field validation for 'UserName' failed")
+// 	})
+// 	t.Run("Empty UserName", func(t *testing.T) {
+// 		t.Skip()
+// 		user.UserName = ""
+// 		err := logic.ValidateUser(&user)
+// 		assert.EqualError(t, err, "some string")
+// 		// assert.Contains(t, err.Error(), "Field validation for 'UserName' failed")
+// 	})
+// 	t.Run("EmptyPassword", func(t *testing.T) {
+// 		user.Password = ""
+// 		err := logic.ValidateUser(&user)
+// 		assert.EqualError(t, err, "Key: 'User.Password' Error:Field validation for 'Password' failed on the 'required' tag")
+// 	})
+// 	t.Run("ShortPassword", func(t *testing.T) {
+// 		user.Password = "123"
+// 		err := logic.ValidateUser(&user)
+// 		assert.EqualError(t, err, "Key: 'User.Password' Error:Field validation for 'Password' failed on the 'min' tag")
+// 	})
+// }
 
-func TestValidateUser(t *testing.T) {
-	var user models.User
-	t.Run("Valid Create", func(t *testing.T) {
-		user.UserName = "admin"
-		user.Password = "validpass"
-		err := logic.ValidateUser(&user)
-		assert.Nil(t, err)
-	})
-	t.Run("Valid Update", func(t *testing.T) {
-		user.UserName = "admin"
-		user.Password = "password"
-		err := logic.ValidateUser(&user)
-		assert.Nil(t, err)
-	})
-	t.Run("Invalid UserName", func(t *testing.T) {
-		t.Skip()
-		user.UserName = "*invalid"
-		err := logic.ValidateUser(&user)
-		assert.Error(t, err)
-		// assert.Contains(t, err.Error(), "Field validation for 'UserName' failed")
-	})
-	t.Run("Short UserName", func(t *testing.T) {
-		t.Skip()
-		user.UserName = "1"
-		err := logic.ValidateUser(&user)
-		assert.NotNil(t, err)
-		// assert.Contains(t, err.Error(), "Field validation for 'UserName' failed")
-	})
-	t.Run("Empty UserName", func(t *testing.T) {
-		t.Skip()
-		user.UserName = ""
-		err := logic.ValidateUser(&user)
-		assert.EqualError(t, err, "some string")
-		// assert.Contains(t, err.Error(), "Field validation for 'UserName' failed")
-	})
-	t.Run("EmptyPassword", func(t *testing.T) {
-		user.Password = ""
-		err := logic.ValidateUser(&user)
-		assert.EqualError(t, err, "Key: 'User.Password' Error:Field validation for 'Password' failed on the 'required' tag")
-	})
-	t.Run("ShortPassword", func(t *testing.T) {
-		user.Password = "123"
-		err := logic.ValidateUser(&user)
-		assert.EqualError(t, err, "Key: 'User.Password' Error:Field validation for 'Password' failed on the 'min' tag")
-	})
-}
+// func TestGetUser(t *testing.T) {
+// 	deleteAllUsers(t)
 
-func TestGetUser(t *testing.T) {
-	deleteAllUsers(t)
+// 	user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
 
-	user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
+// 	t.Run("NonExistantUser", func(t *testing.T) {
+// 		admin, err := logic.GetUser("admin")
+// 		assert.EqualError(t, err, "could not find any records")
+// 		assert.Equal(t, "", admin.UserName)
+// 	})
+// 	t.Run("UserExisits", func(t *testing.T) {
+// 		if err := logic.CreateUser(&user); err != nil {
+// 			t.Error(err)
+// 		}
+// 		admin, err := logic.GetUser("admin")
+// 		assert.Nil(t, err)
+// 		assert.Equal(t, user.UserName, admin.UserName)
+// 	})
+// }
 
-	t.Run("NonExistantUser", func(t *testing.T) {
-		admin, err := logic.GetUser("admin")
-		assert.EqualError(t, err, "could not find any records")
-		assert.Equal(t, "", admin.UserName)
-	})
-	t.Run("UserExisits", func(t *testing.T) {
-		if err := logic.CreateUser(&user); err != nil {
-			t.Error(err)
-		}
-		admin, err := logic.GetUser("admin")
-		assert.Nil(t, err)
-		assert.Equal(t, user.UserName, admin.UserName)
-	})
-}
+// func TestGetUsers(t *testing.T) {
+// 	deleteAllUsers(t)
 
-func TestGetUsers(t *testing.T) {
-	deleteAllUsers(t)
+// 	adminUser := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
+// 	user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
 
-	adminUser := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
-	user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
+// 	t.Run("NonExistantUser", func(t *testing.T) {
+// 		admin, err := logic.GetUsers()
+// 		assert.EqualError(t, err, "could not find any records")
+// 		assert.Equal(t, []models.ReturnUser(nil), admin)
+// 	})
+// 	t.Run("UserExisits", func(t *testing.T) {
+// 		user.UserName = "anotheruser"
+// 		if err := logic.CreateUser(&adminUser); err != nil {
+// 			t.Error(err)
+// 		}
+// 		admins, err := logic.GetUsers()
+// 		assert.Nil(t, err)
+// 		assert.Equal(t, adminUser.UserName, admins[0].UserName)
+// 	})
+// 	t.Run("MulipleUsers", func(t *testing.T) {
+// 		if err := logic.CreateUser(&user); err != nil {
+// 			t.Error(err)
+// 		}
+// 		admins, err := logic.GetUsers()
+// 		assert.Nil(t, err)
+// 		for _, u := range admins {
+// 			if u.UserName == "admin" {
+// 				assert.Equal(t, true, u.IsAdmin)
+// 			} else {
+// 				assert.Equal(t, user.UserName, u.UserName)
+// 				assert.Equal(t, user.PlatformRoleID, u.PlatformRoleID)
+// 			}
+// 		}
+// 	})
 
-	t.Run("NonExistantUser", func(t *testing.T) {
-		admin, err := logic.GetUsers()
-		assert.EqualError(t, err, "could not find any records")
-		assert.Equal(t, []models.ReturnUser(nil), admin)
-	})
-	t.Run("UserExisits", func(t *testing.T) {
-		user.UserName = "anotheruser"
-		if err := logic.CreateUser(&adminUser); err != nil {
-			t.Error(err)
-		}
-		admins, err := logic.GetUsers()
-		assert.Nil(t, err)
-		assert.Equal(t, adminUser.UserName, admins[0].UserName)
-	})
-	t.Run("MulipleUsers", func(t *testing.T) {
-		if err := logic.CreateUser(&user); err != nil {
-			t.Error(err)
-		}
-		admins, err := logic.GetUsers()
-		assert.Nil(t, err)
-		for _, u := range admins {
-			if u.UserName == "admin" {
-				assert.Equal(t, true, u.IsAdmin)
-			} else {
-				assert.Equal(t, user.UserName, u.UserName)
-				assert.Equal(t, user.PlatformRoleID, u.PlatformRoleID)
-			}
-		}
-	})
+// }
 
-}
+// func TestUpdateUser(t *testing.T) {
+// 	deleteAllUsers(t)
+// 	user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
+// 	newuser := models.User{UserName: "hello", Password: "world", PlatformRoleID: models.AdminRole}
+// 	t.Run("NonExistantUser", func(t *testing.T) {
+// 		admin, err := logic.UpdateUser(&newuser, &user)
+// 		assert.EqualError(t, err, "could not find any records")
+// 		assert.Equal(t, "", admin.UserName)
+// 	})
 
-func TestUpdateUser(t *testing.T) {
-	deleteAllUsers(t)
-	user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
-	newuser := models.User{UserName: "hello", Password: "world", PlatformRoleID: models.AdminRole}
-	t.Run("NonExistantUser", func(t *testing.T) {
-		admin, err := logic.UpdateUser(&newuser, &user)
-		assert.EqualError(t, err, "could not find any records")
-		assert.Equal(t, "", admin.UserName)
-	})
+// 	t.Run("UserExists", func(t *testing.T) {
+// 		if err := logic.CreateUser(&user); err != nil {
+// 			t.Error(err)
+// 		}
+// 		admin, err := logic.UpdateUser(&newuser, &user)
+// 		assert.Nil(t, err)
+// 		assert.Equal(t, newuser.UserName, admin.UserName)
+// 	})
+// }
 
-	t.Run("UserExists", func(t *testing.T) {
-		if err := logic.CreateUser(&user); err != nil {
-			t.Error(err)
-		}
-		admin, err := logic.UpdateUser(&newuser, &user)
-		assert.Nil(t, err)
-		assert.Equal(t, newuser.UserName, admin.UserName)
-	})
-}
+// // func TestValidateUserToken(t *testing.T) {
+// // 	t.Run("EmptyToken", func(t *testing.T) {
+// // 		err := ValidateUserToken("", "", false)
+// // 		assert.NotNil(t, err)
+// // 		assert.Equal(t, "Missing Auth Token.", err.Error())
+// // 	})
+// // 	t.Run("InvalidToken", func(t *testing.T) {
+// // 		err := ValidateUserToken("Bearer: badtoken", "", false)
+// // 		assert.NotNil(t, err)
+// // 		assert.Equal(t, "Error Verifying Auth Token", err.Error())
+// // 	})
+// // 	t.Run("InvalidUser", func(t *testing.T) {
+// // 		t.Skip()
+// // 		err := ValidateUserToken("Bearer: secretkey", "baduser", false)
+// // 		assert.NotNil(t, err)
+// // 		assert.Equal(t, "Error Verifying Auth Token", err.Error())
+// // 		//need authorization
+// // 	})
+// // 	t.Run("ValidToken", func(t *testing.T) {
+// // 		err := ValidateUserToken("Bearer: secretkey", "", true)
+// // 		assert.Nil(t, err)
+// // 	})
+// // }
 
-// func TestValidateUserToken(t *testing.T) {
-// 	t.Run("EmptyToken", func(t *testing.T) {
-// 		err := ValidateUserToken("", "", false)
-// 		assert.NotNil(t, err)
-// 		assert.Equal(t, "Missing Auth Token.", err.Error())
+// func TestVerifyAuthRequest(t *testing.T) {
+// 	deleteAllUsers(t)
+// 	user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
+// 	var authRequest models.UserAuthParams
+// 	t.Run("EmptyUserName", func(t *testing.T) {
+// 		authRequest.UserName = ""
+// 		authRequest.Password = "Password"
+// 		jwt, err := logic.VerifyAuthRequest(authRequest)
+// 		assert.Equal(t, "", jwt)
+// 		assert.EqualError(t, err, "username can't be empty")
 // 	})
-// 	t.Run("InvalidToken", func(t *testing.T) {
-// 		err := ValidateUserToken("Bearer: badtoken", "", false)
-// 		assert.NotNil(t, err)
-// 		assert.Equal(t, "Error Verifying Auth Token", err.Error())
+// 	t.Run("EmptyPassword", func(t *testing.T) {
+// 		authRequest.UserName = "admin"
+// 		authRequest.Password = ""
+// 		jwt, err := logic.VerifyAuthRequest(authRequest)
+// 		assert.Equal(t, "", jwt)
+// 		assert.EqualError(t, err, "password can't be empty")
 // 	})
-// 	t.Run("InvalidUser", func(t *testing.T) {
-// 		t.Skip()
-// 		err := ValidateUserToken("Bearer: secretkey", "baduser", false)
-// 		assert.NotNil(t, err)
-// 		assert.Equal(t, "Error Verifying Auth Token", err.Error())
-// 		//need authorization
+// 	t.Run("NonExistantUser", func(t *testing.T) {
+// 		authRequest.UserName = "admin"
+// 		authRequest.Password = "password"
+// 		jwt, err := logic.VerifyAuthRequest(authRequest)
+// 		assert.Equal(t, "", jwt)
+// 		assert.EqualError(t, err, "incorrect credentials")
 // 	})
-// 	t.Run("ValidToken", func(t *testing.T) {
-// 		err := ValidateUserToken("Bearer: secretkey", "", true)
+// 	t.Run("Non-Admin", func(t *testing.T) {
+// 		user.PlatformRoleID = models.ServiceUser
+// 		user.Password = "somepass"
+// 		user.UserName = "nonadmin"
+// 		if err := logic.CreateUser(&user); err != nil {
+// 			t.Error(err)
+// 		}
+// 		authRequest := models.UserAuthParams{UserName: "nonadmin", Password: "somepass"}
+// 		jwt, err := logic.VerifyAuthRequest(authRequest)
+// 		assert.NotNil(t, jwt)
 // 		assert.Nil(t, err)
 // 	})
+// 	t.Run("WrongPassword", func(t *testing.T) {
+// 		user := models.User{UserName: "admin", Password: "password"}
+// 		if err := logic.CreateUser(&user); err != nil {
+// 			t.Error(err)
+// 		}
+// 		authRequest := models.UserAuthParams{UserName: "admin", Password: "badpass"}
+// 		jwt, err := logic.VerifyAuthRequest(authRequest)
+// 		assert.Equal(t, "", jwt)
+// 		assert.EqualError(t, err, "incorrect credentials")
+// 	})
+// 	t.Run("Success", func(t *testing.T) {
+// 		authRequest := models.UserAuthParams{UserName: "admin", Password: "password"}
+// 		jwt, err := logic.VerifyAuthRequest(authRequest)
+// 		assert.Nil(t, err)
+// 		assert.NotNil(t, jwt)
+// 	})
 // }
-
-func TestVerifyAuthRequest(t *testing.T) {
-	deleteAllUsers(t)
-	user := models.User{UserName: "admin", Password: "password", PlatformRoleID: models.AdminRole}
-	var authRequest models.UserAuthParams
-	t.Run("EmptyUserName", func(t *testing.T) {
-		authRequest.UserName = ""
-		authRequest.Password = "Password"
-		jwt, err := logic.VerifyAuthRequest(authRequest)
-		assert.Equal(t, "", jwt)
-		assert.EqualError(t, err, "username can't be empty")
-	})
-	t.Run("EmptyPassword", func(t *testing.T) {
-		authRequest.UserName = "admin"
-		authRequest.Password = ""
-		jwt, err := logic.VerifyAuthRequest(authRequest)
-		assert.Equal(t, "", jwt)
-		assert.EqualError(t, err, "password can't be empty")
-	})
-	t.Run("NonExistantUser", func(t *testing.T) {
-		authRequest.UserName = "admin"
-		authRequest.Password = "password"
-		jwt, err := logic.VerifyAuthRequest(authRequest)
-		assert.Equal(t, "", jwt)
-		assert.EqualError(t, err, "incorrect credentials")
-	})
-	t.Run("Non-Admin", func(t *testing.T) {
-		user.PlatformRoleID = models.ServiceUser
-		user.Password = "somepass"
-		user.UserName = "nonadmin"
-		if err := logic.CreateUser(&user); err != nil {
-			t.Error(err)
-		}
-		authRequest := models.UserAuthParams{UserName: "nonadmin", Password: "somepass"}
-		jwt, err := logic.VerifyAuthRequest(authRequest)
-		assert.NotNil(t, jwt)
-		assert.Nil(t, err)
-	})
-	t.Run("WrongPassword", func(t *testing.T) {
-		user := models.User{UserName: "admin", Password: "password"}
-		if err := logic.CreateUser(&user); err != nil {
-			t.Error(err)
-		}
-		authRequest := models.UserAuthParams{UserName: "admin", Password: "badpass"}
-		jwt, err := logic.VerifyAuthRequest(authRequest)
-		assert.Equal(t, "", jwt)
-		assert.EqualError(t, err, "incorrect credentials")
-	})
-	t.Run("Success", func(t *testing.T) {
-		authRequest := models.UserAuthParams{UserName: "admin", Password: "password"}
-		jwt, err := logic.VerifyAuthRequest(authRequest)
-		assert.Nil(t, err)
-		assert.NotNil(t, jwt)
-	})
-}

+ 6 - 5
go.mod

@@ -3,7 +3,7 @@ module github.com/gravitl/netmaker
 go 1.19
 
 require (
-	github.com/eclipse/paho.mqtt.golang v1.5.0
+	github.com/eclipse/paho.mqtt.golang v1.4.3
 	github.com/go-playground/validator/v10 v10.22.0
 	github.com/golang-jwt/jwt/v4 v4.5.0
 	github.com/google/uuid v1.6.0
@@ -16,10 +16,10 @@ require (
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/stretchr/testify v1.9.0
 	github.com/txn2/txeh v1.5.5
-	golang.org/x/crypto v0.25.0
-	golang.org/x/net v0.27.0 // indirect
+	golang.org/x/crypto v0.23.0
+	golang.org/x/net v0.23.0 // indirect
 	golang.org/x/oauth2 v0.21.0
-	golang.org/x/sys v0.22.0 // indirect
+	golang.org/x/sys v0.21.0 // indirect
 	golang.org/x/text v0.16.0 // indirect
 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb
 	gopkg.in/yaml.v3 v3.0.1
@@ -28,7 +28,7 @@ require (
 require (
 	filippo.io/edwards25519 v1.1.0
 	github.com/c-robinson/iplib v1.0.8
-	github.com/posthog/posthog-go v1.2.18
+	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
 )
 
 require (
@@ -54,6 +54,7 @@ require (
 	github.com/rivo/uniseg v0.2.0 // indirect
 	github.com/seancfoley/bintree v1.3.1 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
+	github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
 )
 

+ 18 - 0
go.sum

@@ -2,14 +2,18 @@ cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2Qx
 cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
 filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
 filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/c-robinson/iplib v1.0.8 h1:exDRViDyL9UBLcfmlxxkY5odWX5092nPsQIykHXhIn4=
 github.com/c-robinson/iplib v1.0.8/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
 github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo=
 github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
+github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
 github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o=
 github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk=
 github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
@@ -59,6 +63,8 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0 h1:Y2hUrkfuM0on62KZOci/VLijlkdF/yeWU262BQgvcjE=
+github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0/go.mod h1:oa2sAs9tGai3VldabTV0eWejt/O4/OOD7azP8GaikqU=
 github.com/posthog/posthog-go v1.2.18 h1:2CBA0LOB0up+gon+xpeXuhFw69gZpjAYxQoBBGwiDWw=
 github.com/posthog/posthog-go v1.2.18/go.mod h1:QjlpryJtfYLrZF2GUkAhejH4E7WlDbdKkvOi5hLmkdg=
 github.com/resendlabs/resend-go v1.7.0 h1:DycOqSXtw2q7aB+Nt9DDJUDtaYcrNPGn1t5RFposas0=
@@ -68,11 +74,13 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rqlite/gorqlite v0.0.0-20240122221808-a8a425b1a6aa h1:hxMLFbj+F444JAS5nUQxTDZwUxwCRqg3WkNqhiDzXrM=
 github.com/rqlite/gorqlite v0.0.0-20240122221808-a8a425b1a6aa/go.mod h1:xF/KoXmrRyahPfo5L7Szb5cAAUl53dMWBh9cMruGEZg=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/seancfoley/bintree v1.3.1 h1:cqmmQK7Jm4aw8gna0bP+huu5leVOgHGSJBEpUx3EXGI=
 github.com/seancfoley/bintree v1.3.1/go.mod h1:hIUabL8OFYyFVTQ6azeajbopogQc2l5C/hiXMcemWNU=
 github.com/seancfoley/ipaddress-go v1.6.0 h1:9z7yGmOnV4P2ML/dlR/kCJiv5tp8iHOOetJvxJh/R5w=
 github.com/seancfoley/ipaddress-go v1.6.0/go.mod h1:TQRZgv+9jdvzHmKoPGBMxyiaVmoI0rYpfEk8Q/sL/Iw=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
 github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
@@ -85,10 +93,15 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/txn2/txeh v1.5.5 h1:UN4e/lCK5HGw/gGAi2GCVrNKg0GTCUWs7gs5riaZlz4=
 github.com/txn2/txeh v1.5.5/go.mod h1:qYzGG9kCzeVEI12geK4IlanHWY8X4uy/I3NcW7mk8g4=
+github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
+github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
 golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
@@ -100,6 +113,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
+golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
 golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
 golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
@@ -117,6 +132,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
 golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -145,6 +162,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk=
 gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 20 - 17
pro/controllers/users.go

@@ -165,24 +165,27 @@ func inviteUsers(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	callerUserName := r.Header.Get("user")
-	caller, err := logic.GetUser(callerUserName)
-	if err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "notfound"))
-		return
-	}
-	if inviteReq.PlatformRoleID == models.SuperAdminRole.String() {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("super admin cannot be invited"), "badrequest"))
-		return
-	}
-	if inviteReq.PlatformRoleID == "" {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("platform role id cannot be empty"), "badrequest"))
-		return
-	}
-	if (inviteReq.PlatformRoleID == models.AdminRole.String() ||
-		inviteReq.PlatformRoleID == models.SuperAdminRole.String()) && caller.PlatformRoleID != models.SuperAdminRole {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only superadmin can invite admin users"), "forbidden"))
-		return
+	if r.Header.Get("ismaster") != "yes" {
+		caller, err := logic.GetUser(callerUserName)
+		if err != nil {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "notfound"))
+			return
+		}
+		if inviteReq.PlatformRoleID == models.SuperAdminRole.String() {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("super admin cannot be invited"), "badrequest"))
+			return
+		}
+		if inviteReq.PlatformRoleID == "" {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("platform role id cannot be empty"), "badrequest"))
+			return
+		}
+		if (inviteReq.PlatformRoleID == models.AdminRole.String() ||
+			inviteReq.PlatformRoleID == models.SuperAdminRole.String()) && caller.PlatformRoleID != models.SuperAdminRole {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only superadmin can invite admin users"), "forbidden"))
+			return
+		}
 	}
+
 	//validate Req
 	err = proLogic.IsGroupsValid(inviteReq.UserGroups)
 	if err != nil {

+ 7 - 1
pro/email/email.go

@@ -18,12 +18,18 @@ const (
 func init() {
 	switch EmailSenderType(servercfg.EmailSenderType()) {
 	case Smtp:
-		client = &SmtpSender{
+		smtpSender := &SmtpSender{
 			SmtpHost:    servercfg.GetSmtpHost(),
 			SmtpPort:    servercfg.GetSmtpPort(),
 			SenderEmail: servercfg.GetSenderEmail(),
+			SendUser:    servercfg.GetSenderUser(),
 			SenderPass:  servercfg.GetEmaiSenderAuth(),
 		}
+		if smtpSender.SendUser == "" {
+			smtpSender.SendUser = smtpSender.SenderEmail
+		}
+		client = smtpSender
+
 	case Resend:
 		client = NewResendEmailSenderFromConfig()
 	}

+ 2 - 1
pro/email/smtp.go

@@ -11,6 +11,7 @@ type SmtpSender struct {
 	SmtpHost    string
 	SmtpPort    int
 	SenderEmail string
+	SendUser    string
 	SenderPass  string
 }
 
@@ -27,7 +28,7 @@ func (s *SmtpSender) SendEmail(ctx context.Context, n Notification, e Mail) erro
 	// Set E-Mail body. You can set plain text or html with text/html
 	m.SetBody("text/html", e.GetBody(n))
 	// Settings for SMTP server
-	d := gomail.NewDialer(s.SmtpHost, s.SmtpPort, s.SenderEmail, s.SenderPass)
+	d := gomail.NewDialer(s.SmtpHost, s.SmtpPort, s.SendUser, s.SenderPass)
 
 	// This is only needed when SSL/TLS certificate is not valid on server.
 	// In production this should be set to false.

+ 5 - 3
scripts/netmaker.default.env

@@ -82,7 +82,9 @@ SMTP_HOST=smtp.gmail.com
 SMTP_PORT=587
 # sender email
 EMAIL_SENDER_ADDR=
-# sender email auth
-EMAIL_SENDER_AUTH=
+# sender smtp user, if unset sender email will be used
+EMAIL_SENDER_USER=
+# sender smtp password
+EMAIL_SENDER_PASSWORD=
 # mail sender type (smtp or resend)
-EMAIL_SENDER_TYPE=smtp
+EMAIL_SENDER_TYPE=smtp

+ 2 - 1
scripts/nm-quick.sh

@@ -253,7 +253,8 @@ save_config() { (
 		"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT"
 		"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "VERBOSITY"
 		"DEBUG_MODE"  "REST_BACKEND" "DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "ALLOWED_EMAIL_DOMAINS" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
-		"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT" "JWT_VALIDITY_DURATION" "RAC_AUTO_DISABLE" "CACHING_ENABLED" "ENDPOINT_DETECTION")
+		"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT" "JWT_VALIDITY_DURATION" "RAC_AUTO_DISABLE" "CACHING_ENABLED" "ENDPOINT_DETECTION"
+		"SMTP_HOST" "SMTP_PORT" "EMAIL_SENDER_ADDR" "EMAIL_SENDER_USER" "EMAIL_SENDER_PASSWORD" "EMAIL_SENDER_TYPE")
 	for name in "${toCopy[@]}"; do
 		save_config_item $name "${!name}"
 	done

+ 11 - 1
servercfg/serverconf.go

@@ -275,9 +275,19 @@ func GetSenderEmail() string {
 	return v
 }
 
+func GetSenderUser() string {
+	v := ""
+	if fromEnv := os.Getenv("EMAIL_SENDER_USER"); fromEnv != "" {
+		v = fromEnv
+	} else if fromCfg := config.Config.Server.EmailSenderAddr; fromCfg != "" {
+		v = fromCfg
+	}
+	return v
+}
+
 func GetEmaiSenderAuth() string {
 	v := ""
-	if fromEnv := os.Getenv("EMAIL_SENDER_AUTH"); fromEnv != "" {
+	if fromEnv := os.Getenv("EMAIL_SENDER_PASSWORD"); fromEnv != "" {
 		v = fromEnv
 	} else if fromCfg := config.Config.Server.EmailSenderAddr; fromCfg != "" {
 		v = fromCfg