Browse Source

Merge branch 'develop' of https://github.com/gravitl/netmaker into NET-822

abhishek9686 1 year ago
parent
commit
c1f06c6c54

+ 1 - 1
.github/ISSUE_TEMPLATE/bug-report.yml

@@ -31,7 +31,7 @@ body:
       label: Version
       label: Version
       description: What version are you running?
       description: What version are you running?
       options:
       options:
-        - v0.21.3
+        - v0.22.0
         - v0.21.2
         - v0.21.2
         - v0.21.1
         - v0.21.1
         - v0.21.0
         - v0.21.0

+ 4 - 4
.github/workflows/test.yml

@@ -13,7 +13,7 @@ jobs:
       - name: Checkout
       - name: Checkout
         uses: actions/checkout@v4
         uses: actions/checkout@v4
       - name: Setup Go
       - name: Setup Go
-        uses: actions/setup-go@v4
+        uses: actions/setup-go@v5
         with:
         with:
           go-version: 1.19
           go-version: 1.19
       - name: Build
       - name: Build
@@ -27,7 +27,7 @@ jobs:
       - name: Checkout
       - name: Checkout
         uses: actions/checkout@v4
         uses: actions/checkout@v4
       - name: Setup go
       - name: Setup go
-        uses: actions/setup-go@v4
+        uses: actions/setup-go@v5
         with:
         with:
           go-version: 1.19
           go-version: 1.19
       - name: Build
       - name: Build
@@ -44,7 +44,7 @@ jobs:
       - name: Checkout
       - name: Checkout
         uses: actions/checkout@v4
         uses: actions/checkout@v4
       - name: Setup Go
       - name: Setup Go
-        uses: actions/setup-go@v4
+        uses: actions/setup-go@v5
         with:
         with:
           go-version: 1.19
           go-version: 1.19
       - name: run tests
       - name: run tests
@@ -64,7 +64,7 @@ jobs:
       - name: Checkout
       - name: Checkout
         uses: actions/checkout@v4
         uses: actions/checkout@v4
       - name: Setup Go
       - name: Setup Go
-        uses: actions/setup-go@v4
+        uses: actions/setup-go@v5
         with:
         with:
           go-version: 1.19
           go-version: 1.19
       - name: run static checks
       - name: run static checks

+ 1 - 1
Dockerfile

@@ -6,7 +6,7 @@ COPY . .
 
 
 RUN GOOS=linux CGO_ENABLED=1 go build -ldflags="-s -w " -tags ${tags} .
 RUN GOOS=linux CGO_ENABLED=1 go build -ldflags="-s -w " -tags ${tags} .
 # RUN go build -tags=ee . -o netmaker main.go
 # RUN go build -tags=ee . -o netmaker main.go
-FROM alpine:3.18.5
+FROM alpine:3.19.0
 
 
 # add a c lib
 # add a c lib
 # set the working directory
 # set the working directory

+ 1 - 1
Dockerfile-quick

@@ -1,5 +1,5 @@
 #first stage - builder
 #first stage - builder
-FROM alpine:3.18.5
+FROM alpine:3.19.0
 ARG version 
 ARG version 
 WORKDIR /app
 WORKDIR /app
 COPY ./netmaker /root/netmaker
 COPY ./netmaker /root/netmaker

+ 1 - 1
README.md

@@ -16,7 +16,7 @@
 
 
 <p align="center">
 <p align="center">
   <a href="https://github.com/gravitl/netmaker/releases">
   <a href="https://github.com/gravitl/netmaker/releases">
-    <img src="https://img.shields.io/badge/Version-0.21.3-informational?style=flat-square" />
+    <img src="https://img.shields.io/badge/Version-0.22.0-informational?style=flat-square" />
   </a>
   </a>
   <a href="https://hub.docker.com/r/gravitl/netmaker/tags">
   <a href="https://hub.docker.com/r/gravitl/netmaker/tags">
     <img src="https://img.shields.io/docker/pulls/gravitl/netmaker?label=downloads" />
     <img src="https://img.shields.io/docker/pulls/gravitl/netmaker?label=downloads" />

+ 28 - 5
cli/cmd/context/set.go

@@ -1,9 +1,11 @@
 package context
 package context
 
 
 import (
 import (
+	"fmt"
 	"log"
 	"log"
 
 
 	"github.com/gravitl/netmaker/cli/config"
 	"github.com/gravitl/netmaker/cli/config"
+	"github.com/gravitl/netmaker/cli/functions"
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra"
 )
 )
 
 
@@ -13,6 +15,8 @@ var (
 	password  string
 	password  string
 	masterKey string
 	masterKey string
 	sso       bool
 	sso       bool
+	tenantId  string
+	saas      bool
 )
 )
 
 
 var contextSetCmd = &cobra.Command{
 var contextSetCmd = &cobra.Command{
@@ -27,10 +31,28 @@ var contextSetCmd = &cobra.Command{
 			Password:  password,
 			Password:  password,
 			MasterKey: masterKey,
 			MasterKey: masterKey,
 			SSO:       sso,
 			SSO:       sso,
+			TenantId:  tenantId,
+			Saas:      saas,
 		}
 		}
-		if ctx.Username == "" && ctx.MasterKey == "" && !ctx.SSO {
-			cmd.Usage()
-			log.Fatal("Either username/password or master key is required")
+		if !ctx.Saas {
+			if ctx.Username == "" && ctx.MasterKey == "" && !ctx.SSO {
+				log.Fatal("Either username/password or master key is required")
+				cmd.Usage()
+			}
+			if ctx.Endpoint == "" {
+				log.Fatal("Endpoint is required when for self-hosted tenants")
+				cmd.Usage()
+			}
+		} else {
+			if ctx.TenantId == "" {
+				log.Fatal("Tenant ID is required for SaaS tenants")
+				cmd.Usage()
+			}
+			ctx.Endpoint = fmt.Sprintf(functions.TenantUrlTemplate, tenantId)
+			if ctx.Username == "" && ctx.Password == "" && !ctx.SSO {
+				log.Fatal("Username/password is required for non-SSO SaaS contexts")
+				cmd.Usage()
+			}
 		}
 		}
 		config.SetContext(args[0], ctx)
 		config.SetContext(args[0], ctx)
 	},
 	},
@@ -38,11 +60,12 @@ var contextSetCmd = &cobra.Command{
 
 
 func init() {
 func init() {
 	contextSetCmd.Flags().StringVar(&endpoint, "endpoint", "", "Endpoint of the API Server")
 	contextSetCmd.Flags().StringVar(&endpoint, "endpoint", "", "Endpoint of the API Server")
-	contextSetCmd.MarkFlagRequired("endpoint")
 	contextSetCmd.Flags().StringVar(&username, "username", "", "Username")
 	contextSetCmd.Flags().StringVar(&username, "username", "", "Username")
 	contextSetCmd.Flags().StringVar(&password, "password", "", "Password")
 	contextSetCmd.Flags().StringVar(&password, "password", "", "Password")
 	contextSetCmd.MarkFlagsRequiredTogether("username", "password")
 	contextSetCmd.MarkFlagsRequiredTogether("username", "password")
-	contextSetCmd.Flags().BoolVar(&sso, "sso", false, "Login via Single Sign On (SSO) ?")
+	contextSetCmd.Flags().BoolVar(&sso, "sso", false, "Login via Single Sign On (SSO)?")
 	contextSetCmd.Flags().StringVar(&masterKey, "master_key", "", "Master Key")
 	contextSetCmd.Flags().StringVar(&masterKey, "master_key", "", "Master Key")
+	contextSetCmd.Flags().StringVar(&tenantId, "tenant_id", "", "Tenant ID")
+	contextSetCmd.Flags().BoolVar(&saas, "saas", false, "Is this context for a SaaS tenant?")
 	rootCmd.AddCommand(contextSetCmd)
 	rootCmd.AddCommand(contextSetCmd)
 }
 }

+ 2 - 0
cli/config/config.go

@@ -18,6 +18,8 @@ type Context struct {
 	Current   bool   `yaml:"current,omitempty"`
 	Current   bool   `yaml:"current,omitempty"`
 	AuthToken string `yaml:"auth_token,omitempty"`
 	AuthToken string `yaml:"auth_token,omitempty"`
 	SSO       bool   `yaml:"sso,omitempty"`
 	SSO       bool   `yaml:"sso,omitempty"`
+	TenantId  string `yaml:"tenant_id,omitempty"`
+	Saas      bool   `yaml:"saas,omitempty"`
 }
 }
 
 
 var (
 var (

+ 262 - 21
cli/functions/http_client.go

@@ -11,11 +11,19 @@ import (
 	"os"
 	"os"
 	"os/signal"
 	"os/signal"
 	"strings"
 	"strings"
+	"time"
 
 
 	"github.com/gorilla/websocket"
 	"github.com/gorilla/websocket"
 	"github.com/gravitl/netmaker/cli/config"
 	"github.com/gravitl/netmaker/cli/config"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
+	"golang.org/x/exp/slog"
+)
+
+const (
+	ambBaseUrl        = "https://api.accounts.netmaker.io"
+	TenantUrlTemplate = "https://api-%s.app.prod.netmaker.io"
+	ambOauthWssUrl    = "wss://api.accounts.netmaker.io/api/v1/auth/sso"
 )
 )
 
 
 func ssoLogin(endpoint string) string {
 func ssoLogin(endpoint string) string {
@@ -81,34 +89,57 @@ func getAuthToken(ctx config.Context, force bool) string {
 	if !force && ctx.AuthToken != "" {
 	if !force && ctx.AuthToken != "" {
 		return ctx.AuthToken
 		return ctx.AuthToken
 	}
 	}
-	if ctx.SSO {
-		authToken := ssoLogin(ctx.Endpoint)
+	if !ctx.Saas {
+		if ctx.SSO {
+			authToken := ssoLogin(ctx.Endpoint)
+			config.SetAuthToken(authToken)
+			return authToken
+		}
+		authParams := &models.UserAuthParams{UserName: ctx.Username, Password: ctx.Password}
+		payload, err := json.Marshal(authParams)
+		if err != nil {
+			log.Fatal(err)
+		}
+		res, err := http.Post(ctx.Endpoint+"/api/users/adm/authenticate", "application/json", bytes.NewReader(payload))
+		if err != nil {
+			log.Fatal(err)
+		}
+		defer res.Body.Close()
+		resBodyBytes, err := io.ReadAll(res.Body)
+		if err != nil {
+			log.Fatalf("Client could not read response body: %s", err)
+		}
+		if res.StatusCode != http.StatusOK {
+			log.Fatalf("Error Status: %d Response: %s", res.StatusCode, string(resBodyBytes))
+		}
+		body := new(models.SuccessResponse)
+		if err := json.Unmarshal(resBodyBytes, body); err != nil {
+			log.Fatalf("Error unmarshalling JSON: %s", err)
+		}
+		authToken := body.Response.(map[string]any)["AuthToken"].(string)
 		config.SetAuthToken(authToken)
 		config.SetAuthToken(authToken)
 		return authToken
 		return authToken
 	}
 	}
-	authParams := &models.UserAuthParams{UserName: ctx.Username, Password: ctx.Password}
-	payload, err := json.Marshal(authParams)
-	if err != nil {
-		log.Fatal(err)
+
+	if !ctx.SSO {
+		sToken, _, err := basicAuthSaasSignin(ctx.Username, ctx.Password)
+		if err != nil {
+			log.Fatal(err)
+		}
+		authToken, _, err := tenantLogin(ctx, sToken)
+		if err != nil {
+			log.Fatal(err)
+		}
+		config.SetAuthToken(authToken)
+		return authToken
 	}
 	}
-	res, err := http.Post(ctx.Endpoint+"/api/users/adm/authenticate", "application/json", bytes.NewReader(payload))
+
+	accessToken, err := loginSaaSOauth(&models.SsoLoginReqDto{OauthProvider: "oidc"}, ctx.TenantId)
 	if err != nil {
 	if err != nil {
 		log.Fatal(err)
 		log.Fatal(err)
 	}
 	}
-	resBodyBytes, err := io.ReadAll(res.Body)
-	if err != nil {
-		log.Fatalf("Client could not read response body: %s", err)
-	}
-	if res.StatusCode != http.StatusOK {
-		log.Fatalf("Error Status: %d Response: %s", res.StatusCode, string(resBodyBytes))
-	}
-	body := new(models.SuccessResponse)
-	if err := json.Unmarshal(resBodyBytes, body); err != nil {
-		log.Fatalf("Error unmarshalling JSON: %s", err)
-	}
-	authToken := body.Response.(map[string]any)["AuthToken"].(string)
-	config.SetAuthToken(authToken)
-	return authToken
+	config.SetAuthToken(accessToken)
+	return accessToken
 }
 }
 
 
 func request[T any](method, route string, payload any) *T {
 func request[T any](method, route string, payload any) *T {
@@ -188,3 +219,213 @@ func get(route string) string {
 	}
 	}
 	return string(bodyBytes)
 	return string(bodyBytes)
 }
 }
+
+func basicAuthSaasSignin(email, password string) (string, http.Header, error) {
+	payload := models.SignInReqDto{
+		FormFields: []models.FormField{
+			{
+				Id:    "email",
+				Value: email,
+			},
+			{
+				Id:    "password",
+				Value: password,
+			},
+		},
+	}
+
+	var res models.SignInResDto
+
+	// Create a new HTTP client with a timeout
+	client := &http.Client{
+		Timeout: 30 * time.Second,
+	}
+
+	// Create the request body
+	payloadBuf := new(bytes.Buffer)
+	json.NewEncoder(payloadBuf).Encode(payload)
+
+	// Create the request
+	req, err := http.NewRequest("POST", ambBaseUrl+"/auth/signin", payloadBuf)
+	if err != nil {
+		return "", http.Header{}, err
+	}
+	req.Header.Set("Content-Type", "application/json; charset=utf-8")
+	req.Header.Set("rid", "thirdpartyemailpassword")
+
+	// Send the request
+	resp, err := client.Do(req)
+	if err != nil {
+		return "", http.Header{}, err
+	}
+	defer resp.Body.Close()
+
+	// Check the response status code
+	if resp.StatusCode != http.StatusOK {
+		return "", http.Header{}, fmt.Errorf("error authenticating: %s", resp.Status)
+	}
+
+	// Copy the response headers
+	resHeaders := resp.Header
+
+	// Decode the response body
+	err = json.NewDecoder(resp.Body).Decode(&res)
+	if err != nil {
+		return "", http.Header{}, err
+	}
+
+	sToken := resHeaders.Get(models.ResHeaderKeyStAccessToken)
+	encodedAccessToken := url.QueryEscape(sToken)
+
+	return encodedAccessToken, resHeaders, nil
+}
+
+func tenantLogin(ctx config.Context, sToken string) (string, string, error) {
+	url := fmt.Sprintf("%s/api/v1/tenant/login?tenant_id=%s", ambBaseUrl, ctx.TenantId)
+
+	client := &http.Client{}
+	req, err := http.NewRequest(http.MethodPost, url, nil)
+
+	if err != nil {
+		return "", "", err
+	}
+	req.Header.Add("Cookie", fmt.Sprintf("sAccessToken=%s", sToken))
+
+	res, err := client.Do(req)
+	if err != nil {
+		return "", "", err
+	}
+	defer res.Body.Close()
+
+	body, err := io.ReadAll(res.Body)
+	if err != nil {
+		return "", "", err
+	}
+
+	data := models.TenantLoginResDto{}
+	json.Unmarshal(body, &data)
+
+	return data.Response.AuthToken, fmt.Sprintf(TenantUrlTemplate, ctx.TenantId), nil
+}
+
+func loginSaaSOauth(payload *models.SsoLoginReqDto, tenantId string) (string, error) {
+	socketUrl := ambOauthWssUrl
+	// Dial the netmaker server controller
+	conn, _, err := websocket.DefaultDialer.Dial(socketUrl, nil)
+	if err != nil {
+		slog.Error("error connecting to endpoint ", "url", socketUrl, "err", err)
+		return "", err
+	}
+
+	defer conn.Close()
+	return handleServerSSORegisterConn(payload, conn, tenantId)
+}
+
+func handleServerSSORegisterConn(payload *models.SsoLoginReqDto, conn *websocket.Conn, tenantId string) (string, error) {
+	reqData, err := json.Marshal(payload)
+	if err != nil {
+		return "", err
+	}
+	if err := conn.WriteMessage(websocket.TextMessage, reqData); err != nil {
+		return "", err
+	}
+	dataCh := make(chan string)
+	defer close(dataCh)
+	interrupt := make(chan os.Signal, 1)
+	signal.Notify(interrupt, os.Interrupt)
+
+	go func() {
+		for {
+			msgType, msg, err := conn.ReadMessage()
+			if err != nil {
+				if msgType < 0 {
+					slog.Info("received close message from server")
+					return
+				}
+				if !strings.Contains(err.Error(), "normal") { // Error reading a message from the server
+					slog.Error("error msg", "err", err)
+				}
+				return
+			}
+			if msgType == websocket.CloseMessage {
+				slog.Info("received close message from server")
+				return
+			}
+			if strings.Contains(string(msg), "auth/sso") {
+				fmt.Printf("Please visit:\n %s \nto authenticate\n", string(msg))
+			} else {
+				var res models.SsoLoginData
+				if err := json.Unmarshal(msg, &res); err != nil {
+					return
+				}
+				accessToken, _, err := tenantLoginV2(res.AmbAccessToken, tenantId, res.Username)
+				if err != nil {
+					slog.Error("error logging in tenant", "err", err)
+					dataCh <- ""
+					return
+				}
+				dataCh <- accessToken
+				return
+			}
+		}
+	}()
+
+	for {
+		select {
+		case accessToken := <-dataCh:
+			if accessToken == "" {
+				slog.Info("error getting access token")
+				return "", fmt.Errorf("error getting access token")
+			}
+			return accessToken, nil
+		case <-time.After(30 * time.Second):
+			slog.Error("authentiation timed out")
+			os.Exit(1)
+		case <-interrupt:
+			slog.Info("interrupt received, closing connection")
+			// Cleanly close the connection by sending a close message and then
+			// waiting (with timeout) for the server to close the connection.
+			err := conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
+			if err != nil {
+				log.Fatal(err)
+			}
+			os.Exit(1)
+		}
+	}
+}
+
+func tenantLoginV2(ambJwt, tenantId, email string) (string, string, error) {
+	url := fmt.Sprintf("%s/api/v1/tenant/login/custom", ambBaseUrl)
+	payload := models.LoginReqDto{
+		Email:    email,
+		TenantID: tenantId,
+	}
+	payloadBuf := new(bytes.Buffer)
+	json.NewEncoder(payloadBuf).Encode(payload)
+
+	client := &http.Client{}
+	req, err := http.NewRequest("POST", url, payloadBuf)
+	if err != nil {
+		slog.Error("error creating request", "err", err)
+		return "", "", err
+	}
+	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", ambJwt))
+
+	res, err := client.Do(req)
+	if err != nil {
+		slog.Error("error sending request", "err", err)
+		return "", "", err
+	}
+	defer res.Body.Close()
+
+	body, err := io.ReadAll(res.Body)
+	if err != nil {
+		slog.Error("error reading response body", "err", err)
+		return "", "", err
+	}
+
+	data := models.TenantLoginResDto{}
+	json.Unmarshal(body, &data)
+
+	return data.Response.AuthToken, fmt.Sprintf(TenantUrlTemplate, tenantId), nil
+}

+ 1 - 1
compose/docker-compose.netclient.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netclient:
   netclient:
     container_name: netclient
     container_name: netclient
-    image: 'gravitl/netclient:v0.21.3'
+    image: 'gravitl/netclient:v0.22.0'
     hostname: netmaker-1
     hostname: netmaker-1
     network_mode: host
     network_mode: host
     restart: on-failure
     restart: on-failure

+ 1 - 21
compose/docker-compose.yml

@@ -25,10 +25,6 @@ services:
       - COREDNS_ADDR=${SERVER_HOST}
       - COREDNS_ADDR=${SERVER_HOST}
       # Overrides SERVER_HOST if set. Useful for making HTTP available via different interfaces/networks.
       # Overrides SERVER_HOST if set. Useful for making HTTP available via different interfaces/networks.
       - SERVER_HTTP_HOST=api.${NM_DOMAIN}
       - SERVER_HTTP_HOST=api.${NM_DOMAIN}
-      # domain for your turn server
-      - TURN_SERVER_HOST=turn.${NM_DOMAIN}
-      # domain of the turn api server
-      - TURN_SERVER_API_HOST=https://turnapi.${NM_DOMAIN}
 
 
   netmaker-ui:
   netmaker-ui:
     container_name: netmaker-ui
     container_name: netmaker-ui
@@ -82,22 +78,6 @@ services:
       - ./wait.sh:/mosquitto/config/wait.sh
       - ./wait.sh:/mosquitto/config/wait.sh
       - mosquitto_logs:/mosquitto/log
       - mosquitto_logs:/mosquitto/log
       - mosquitto_data:/mosquitto/data
       - mosquitto_data:/mosquitto/data
-
-  turn:
-    container_name: turn
-    image: gravitl/turnserver:v1.0.0
-    env_file: ./netmaker.env
-    environment:
-      # config-dependant vars
-      - USERNAME=${TURN_USERNAME}
-      - PASSWORD=${TURN_PASSWORD}
-      # domain for your turn server
-      - TURN_SERVER_HOST=turn.${NM_DOMAIN}
-    network_mode: "host"
-    volumes:
-      - turn_server:/etc/config
-    restart: always
-
 volumes:
 volumes:
   caddy_data: { } # runtime data for caddy
   caddy_data: { } # runtime data for caddy
   caddy_conf: { } # configuration file for Caddy
   caddy_conf: { } # configuration file for Caddy
@@ -105,4 +85,4 @@ volumes:
   dnsconfig: { } # storage for coredns
   dnsconfig: { } # storage for coredns
   mosquitto_logs: { } # storage for mqtt logs
   mosquitto_logs: { } # storage for mqtt logs
   mosquitto_data: { } # storage for mqtt data
   mosquitto_data: { } # storage for mqtt data
-  turn_server: { }
+

+ 1 - 1
controllers/docs.go

@@ -10,7 +10,7 @@
 //
 //
 //	Schemes: https
 //	Schemes: https
 //	BasePath: /
 //	BasePath: /
-//	Version: 0.21.3
+//	Version: 0.22.0
 //	Host: api.demo.netmaker.io
 //	Host: api.demo.netmaker.io
 //
 //
 //	Consumes:
 //	Consumes:

+ 0 - 7
controllers/enrollmentkeys.go

@@ -231,13 +231,6 @@ func handleHostRegister(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 		return
 	}
 	}
-	// re-register host with turn just in case.
-	if servercfg.IsUsingTurn() {
-		err = logic.RegisterHostWithTurn(newHost.ID.String(), newHost.HostPass)
-		if err != nil {
-			logger.Log(0, "failed to register host with turn server: ", err.Error())
-		}
-	}
 	// check if host already exists
 	// check if host already exists
 	hostExists := false
 	hostExists := false
 	if hostExists = logic.HostExists(&newHost); hostExists && len(enrollmentKey.Networks) == 0 {
 	if hostExists = logic.HostExists(&newHost); hostExists && len(enrollmentKey.Networks) == 0 {

+ 2 - 7
controllers/hosts.go

@@ -544,19 +544,14 @@ func signalPeer(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 		return
 	}
 	}
-	if signal.ToHostPubKey == "" || (!servercfg.IsPro && signal.TurnRelayEndpoint == "") {
+	if signal.ToHostPubKey == "" {
 		msg := "insufficient data to signal peer"
 		msg := "insufficient data to signal peer"
 		logger.Log(0, r.Header.Get("user"), msg)
 		logger.Log(0, r.Header.Get("user"), msg)
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New(msg), "badrequest"))
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New(msg), "badrequest"))
 		return
 		return
 	}
 	}
 	signal.IsPro = servercfg.IsPro
 	signal.IsPro = servercfg.IsPro
-	var peerHost *models.Host
-	if signal.ToHostID == "" {
-		peerHost, err = logic.GetHostByPubKey(signal.ToHostPubKey)
-	} else {
-		peerHost, err = logic.GetHost(signal.ToHostID)
-	}
+	peerHost, err := logic.GetHost(signal.ToHostID)
 	if err != nil {
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to signal, peer not found"), "badrequest"))
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to signal, peer not found"), "badrequest"))
 		return
 		return

+ 35 - 0
controllers/network.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"net"
 	"net/http"
 	"net/http"
 	"strings"
 	"strings"
 
 
@@ -246,6 +247,40 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 
 
+	// validate address ranges: must be private
+	if network.AddressRange != "" {
+		_, ipNet, err := net.ParseCIDR(network.AddressRange)
+		if err != nil {
+			logger.Log(0, r.Header.Get("user"), "failed to create network: ",
+				err.Error())
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+			return
+		}
+		if !ipNet.IP.IsPrivate() {
+			err := errors.New("address range must be private")
+			logger.Log(0, r.Header.Get("user"), "failed to create network: ",
+				err.Error())
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+			return
+		}
+	}
+	if network.AddressRange6 != "" {
+		_, ipNet, err := net.ParseCIDR(network.AddressRange6)
+		if err != nil {
+			logger.Log(0, r.Header.Get("user"), "failed to create network: ",
+				err.Error())
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+			return
+		}
+		if !ipNet.IP.IsPrivate() {
+			err := errors.New("address range must be private")
+			logger.Log(0, r.Header.Get("user"), "failed to create network: ",
+				err.Error())
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+			return
+		}
+	}
+
 	network, err = logic.CreateNetwork(network)
 	network, err = logic.CreateNetwork(network)
 	if err != nil {
 	if err != nil {
 		logger.Log(0, r.Header.Get("user"), "failed to create network: ",
 		logger.Log(0, r.Header.Get("user"), "failed to create network: ",

+ 0 - 10
docker/Caddyfile

@@ -24,16 +24,6 @@ https://api.{$NM_DOMAIN} {
 	reverse_proxy http://netmaker:8081
 	reverse_proxy http://netmaker:8081
 }
 }
 
 
-# TURN
-https://turn.{$NM_DOMAIN} {
-	reverse_proxy host.docker.internal:3479
-}
-
-# TURN API
-https://turnapi.{$NM_DOMAIN} {
-	reverse_proxy http://host.docker.internal:8089
-}
-
 # MQ
 # MQ
 wss://broker.{$NM_DOMAIN} {
 wss://broker.{$NM_DOMAIN} {
 	reverse_proxy ws://mq:8883 # For EMQX websockets use `reverse_proxy ws://mq:8083`
 	reverse_proxy ws://mq:8883 # For EMQX websockets use `reverse_proxy ws://mq:8083`

+ 0 - 10
docker/Caddyfile-pro

@@ -39,16 +39,6 @@ https://api.{$NM_DOMAIN} {
 	reverse_proxy http://netmaker:8081
 	reverse_proxy http://netmaker:8081
 }
 }
 
 
-# TURN
-https://turn.{$NM_DOMAIN} {
-	reverse_proxy host.docker.internal:3479
-}
-
-# TURN API
-https://turnapi.{$NM_DOMAIN} {
-	reverse_proxy http://host.docker.internal:8089
-}
-
 # MQ
 # MQ
 wss://broker.{$NM_DOMAIN} {
 wss://broker.{$NM_DOMAIN} {
 	reverse_proxy ws://mq:8883
 	reverse_proxy ws://mq:8883

+ 2 - 2
go.mod

@@ -26,13 +26,13 @@ require (
 )
 )
 
 
 require (
 require (
-	filippo.io/edwards25519 v1.0.0
+	filippo.io/edwards25519 v1.1.0
 	github.com/c-robinson/iplib v1.0.7
 	github.com/c-robinson/iplib v1.0.7
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
 )
 )
 
 
 require (
 require (
-	github.com/coreos/go-oidc/v3 v3.8.0
+	github.com/coreos/go-oidc/v3 v3.9.0
 	github.com/gorilla/websocket v1.5.1
 	github.com/gorilla/websocket v1.5.1
 	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
 	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
 )
 )

+ 4 - 4
go.sum

@@ -2,13 +2,13 @@ cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZN
 cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
 cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
 cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
 cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
-filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
-filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
+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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/c-robinson/iplib v1.0.7 h1:Dh9AINAlkc+NsNzZuFiVs+pi3AjN+0B7mu01KHdJKHU=
 github.com/c-robinson/iplib v1.0.7 h1:Dh9AINAlkc+NsNzZuFiVs+pi3AjN+0B7mu01KHdJKHU=
 github.com/c-robinson/iplib v1.0.7/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
 github.com/c-robinson/iplib v1.0.7/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
-github.com/coreos/go-oidc/v3 v3.8.0 h1:s3e30r6VEl3/M7DTSCEuImmrfu1/1WBgA0cXkdzkrAY=
-github.com/coreos/go-oidc/v3 v3.8.0/go.mod h1:yQzSCqBnK3e6Fs5l+f5i0F8Kwf0zpH9bPEsbY00KanM=
+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.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/cpuguy83/go-md2man/v2 v2.0.3/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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

+ 1 - 1
k8s/client/netclient-daemonset.yaml

@@ -16,7 +16,7 @@ spec:
       hostNetwork: true
       hostNetwork: true
       containers:
       containers:
       - name: netclient
       - name: netclient
-        image: gravitl/netclient:v0.21.3
+        image: gravitl/netclient:v0.22.0
         env:
         env:
         - name: TOKEN
         - name: TOKEN
           value: "TOKEN_VALUE"
           value: "TOKEN_VALUE"

+ 1 - 1
k8s/client/netclient.yaml

@@ -28,7 +28,7 @@ spec:
       #           - "<node label value>"
       #           - "<node label value>"
       containers:
       containers:
       - name: netclient
       - name: netclient
-        image: gravitl/netclient:v0.21.3
+        image: gravitl/netclient:v0.22.0
         env:
         env:
         - name: TOKEN
         - name: TOKEN
           value: "TOKEN_VALUE"
           value: "TOKEN_VALUE"

+ 1 - 1
k8s/server/netmaker-ui.yaml

@@ -15,7 +15,7 @@ spec:
     spec:
     spec:
       containers:
       containers:
       - name: netmaker-ui
       - name: netmaker-ui
-        image: gravitl/netmaker-ui:v0.21.3
+        image: gravitl/netmaker-ui:v0.22.0
         ports:
         ports:
         - containerPort: 443
         - containerPort: 443
         env:
         env:

+ 0 - 63
logic/hosts.go

@@ -2,16 +2,12 @@ package logic
 
 
 import (
 import (
 	"crypto/md5"
 	"crypto/md5"
-	"encoding/base64"
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
-	"net/http"
 	"sort"
 	"sort"
-	"strconv"
 	"sync"
 	"sync"
 
 
-	"github.com/devilcove/httpclient"
 	"github.com/google/uuid"
 	"github.com/google/uuid"
 	"golang.org/x/crypto/bcrypt"
 	"golang.org/x/crypto/bcrypt"
 
 
@@ -197,12 +193,6 @@ func CreateHost(h *models.Host) error {
 	if (err != nil && !database.IsEmptyRecord(err)) || (err == nil) {
 	if (err != nil && !database.IsEmptyRecord(err)) || (err == nil) {
 		return ErrHostExists
 		return ErrHostExists
 	}
 	}
-	if servercfg.IsUsingTurn() {
-		err = RegisterHostWithTurn(h.ID.String(), h.HostPass)
-		if err != nil {
-			logger.Log(0, "failed to register host with turn server: ", err.Error())
-		}
-	}
 
 
 	// encrypt that password so we never see it
 	// encrypt that password so we never see it
 	hash, err := bcrypt.GenerateFromPassword([]byte(h.HostPass), 5)
 	hash, err := bcrypt.GenerateFromPassword([]byte(h.HostPass), 5)
@@ -306,10 +296,6 @@ func RemoveHost(h *models.Host, forceDelete bool) error {
 		return fmt.Errorf("host still has associated nodes")
 		return fmt.Errorf("host still has associated nodes")
 	}
 	}
 
 
-	if servercfg.IsUsingTurn() {
-		DeRegisterHostWithTurn(h.ID.String())
-	}
-
 	if len(h.Nodes) > 0 {
 	if len(h.Nodes) > 0 {
 		if err := DisassociateAllNodesFromHost(h.ID.String()); err != nil {
 		if err := DisassociateAllNodesFromHost(h.ID.String()); err != nil {
 			return err
 			return err
@@ -329,9 +315,6 @@ func RemoveHost(h *models.Host, forceDelete bool) error {
 
 
 // RemoveHostByID - removes a given host by id from server
 // RemoveHostByID - removes a given host by id from server
 func RemoveHostByID(hostID string) error {
 func RemoveHostByID(hostID string) error {
-	if servercfg.IsUsingTurn() {
-		DeRegisterHostWithTurn(hostID)
-	}
 
 
 	err := database.DeleteRecord(database.HOSTS_TABLE_NAME, hostID)
 	err := database.DeleteRecord(database.HOSTS_TABLE_NAME, hostID)
 	if err != nil {
 	if err != nil {
@@ -568,52 +551,6 @@ func ConvHostPassToHash(hostPass string) string {
 	return fmt.Sprintf("%x", md5.Sum([]byte(hostPass)))
 	return fmt.Sprintf("%x", md5.Sum([]byte(hostPass)))
 }
 }
 
 
-// RegisterHostWithTurn - registers the host with the given turn server
-func RegisterHostWithTurn(hostID, hostPass string) error {
-	auth := servercfg.GetTurnUserName() + ":" + servercfg.GetTurnPassword()
-	api := httpclient.JSONEndpoint[models.SuccessResponse, models.ErrorResponse]{
-		URL:           servercfg.GetTurnApiHost(),
-		Route:         "/api/v1/host/register",
-		Method:        http.MethodPost,
-		Authorization: fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(auth))),
-		Data: models.HostTurnRegister{
-			HostID:       hostID,
-			HostPassHash: ConvHostPassToHash(hostPass),
-		},
-		Response:      models.SuccessResponse{},
-		ErrorResponse: models.ErrorResponse{},
-	}
-	_, errData, err := api.GetJSON(models.SuccessResponse{}, models.ErrorResponse{})
-	if err != nil {
-		if errors.Is(err, httpclient.ErrStatus) {
-			logger.Log(1, "error server status", strconv.Itoa(errData.Code), errData.Message)
-		}
-		return err
-	}
-	return nil
-}
-
-// DeRegisterHostWithTurn - to be called when host need to be deregistered from a turn server
-func DeRegisterHostWithTurn(hostID string) error {
-	auth := servercfg.GetTurnUserName() + ":" + servercfg.GetTurnPassword()
-	api := httpclient.JSONEndpoint[models.SuccessResponse, models.ErrorResponse]{
-		URL:           servercfg.GetTurnApiHost(),
-		Route:         fmt.Sprintf("/api/v1/host/deregister?host_id=%s", hostID),
-		Method:        http.MethodPost,
-		Authorization: fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(auth))),
-		Response:      models.SuccessResponse{},
-		ErrorResponse: models.ErrorResponse{},
-	}
-	_, errData, err := api.GetJSON(models.SuccessResponse{}, models.ErrorResponse{})
-	if err != nil {
-		if errors.Is(err, httpclient.ErrStatus) {
-			logger.Log(1, "error server status", strconv.Itoa(errData.Code), errData.Message)
-		}
-		return err
-	}
-	return nil
-}
-
 // SortApiHosts - Sorts slice of ApiHosts by their ID alphabetically with numbers first
 // SortApiHosts - Sorts slice of ApiHosts by their ID alphabetically with numbers first
 func SortApiHosts(unsortedHosts []models.ApiHost) {
 func SortApiHosts(unsortedHosts []models.ApiHost) {
 	sort.Slice(unsortedHosts, func(i, j int) bool {
 	sort.Slice(unsortedHosts, func(i, j int) bool {

+ 1 - 1
main.go

@@ -28,7 +28,7 @@ import (
 	"golang.org/x/exp/slog"
 	"golang.org/x/exp/slog"
 )
 )
 
 
-var version = "v0.21.3"
+var version = "v0.22.0"
 
 
 // Start DB Connection and start API Request Handler
 // Start DB Connection and start API Request Handler
 func main() {
 func main() {

+ 11 - 16
models/host.go

@@ -110,8 +110,6 @@ const (
 	RequestAck HostMqAction = "REQ_ACK"
 	RequestAck HostMqAction = "REQ_ACK"
 	// CheckIn - update last check in times and public address and interfaces
 	// CheckIn - update last check in times and public address and interfaces
 	CheckIn HostMqAction = "CHECK_IN"
 	CheckIn HostMqAction = "CHECK_IN"
-	// RegisterWithTurn - registers host with turn server if configured
-	RegisterWithTurn HostMqAction = "REGISTER_WITH_TURN"
 	// UpdateKeys - update wireguard private/public keys
 	// UpdateKeys - update wireguard private/public keys
 	UpdateKeys HostMqAction = "UPDATE_KEYS"
 	UpdateKeys HostMqAction = "UPDATE_KEYS"
 	// RequestPull - request a pull from a host
 	// RequestPull - request a pull from a host
@@ -122,8 +120,6 @@ const (
 type SignalAction string
 type SignalAction string
 
 
 const (
 const (
-	// Disconnect - action to stop using turn connection
-	Disconnect SignalAction = "DISCONNECT"
 	// ConnNegotiation - action to negotiate connection between peers
 	// ConnNegotiation - action to negotiate connection between peers
 	ConnNegotiation SignalAction = "CONNECTION_NEGOTIATION"
 	ConnNegotiation SignalAction = "CONNECTION_NEGOTIATION"
 	// RelayME - action to relay the peer
 	// RelayME - action to relay the peer
@@ -146,18 +142,17 @@ type HostTurnRegister struct {
 
 
 // Signal - struct for signalling peer
 // Signal - struct for signalling peer
 type Signal struct {
 type Signal struct {
-	Server            string       `json:"server"`
-	FromHostPubKey    string       `json:"from_host_pubkey"`
-	TurnRelayEndpoint string       `json:"turn_relay_addr"`
-	ToHostPubKey      string       `json:"to_host_pubkey"`
-	FromHostID        string       `json:"from_host_id"`
-	ToHostID          string       `json:"to_host_id"`
-	FromNodeID        string       `json:"from_node_id"`
-	ToNodeID          string       `json:"to_node_id"`
-	Reply             bool         `json:"reply"`
-	Action            SignalAction `json:"action"`
-	IsPro             bool         `json:"is_pro"`
-	TimeStamp         int64        `json:"timestamp"`
+	Server         string       `json:"server"`
+	FromHostPubKey string       `json:"from_host_pubkey"`
+	ToHostPubKey   string       `json:"to_host_pubkey"`
+	FromHostID     string       `json:"from_host_id"`
+	ToHostID       string       `json:"to_host_id"`
+	FromNodeID     string       `json:"from_node_id"`
+	ToNodeID       string       `json:"to_node_id"`
+	Reply          bool         `json:"reply"`
+	Action         SignalAction `json:"action"`
+	IsPro          bool         `json:"is_pro"`
+	TimeStamp      int64        `json:"timestamp"`
 }
 }
 
 
 // RegisterMsg - login message struct for hosts to join via SSO login
 // RegisterMsg - login message struct for hosts to join via SSO login

+ 51 - 4
models/structs.go

@@ -264,11 +264,7 @@ type ServerConfig struct {
 	Server      string `yaml:"server"`
 	Server      string `yaml:"server"`
 	Broker      string `yaml:"broker"`
 	Broker      string `yaml:"broker"`
 	IsPro       bool   `yaml:"isee" json:"Is_EE"`
 	IsPro       bool   `yaml:"isee" json:"Is_EE"`
-	StunPort    int    `yaml:"stun_port"`
 	TrafficKey  []byte `yaml:"traffickey"`
 	TrafficKey  []byte `yaml:"traffickey"`
-	TurnDomain  string `yaml:"turn_domain"`
-	TurnPort    int    `yaml:"turn_port"`
-	UseTurn     bool   `yaml:"use_turn"`
 }
 }
 
 
 // User.NameInCharset - returns if name is in charset below or not
 // User.NameInCharset - returns if name is in charset below or not
@@ -308,3 +304,54 @@ type LicenseLimits struct {
 	Clients  int `json:"clients"`
 	Clients  int `json:"clients"`
 	Networks int `json:"networks"`
 	Networks int `json:"networks"`
 }
 }
+
+type SignInReqDto struct {
+	FormFields FormFields `json:"formFields"`
+}
+
+type FormField struct {
+	Id    string `json:"id"`
+	Value any    `json:"value"`
+}
+
+type FormFields []FormField
+
+type SignInResDto struct {
+	Status string `json:"status"`
+	User   User   `json:"user"`
+}
+
+type TenantLoginResDto struct {
+	Code     int    `json:"code"`
+	Message  string `json:"message"`
+	Response struct {
+		UserName  string `json:"UserName"`
+		AuthToken string `json:"AuthToken"`
+	} `json:"response"`
+}
+
+type SsoLoginReqDto struct {
+	OauthProvider string `json:"oauthprovider"`
+}
+
+type SsoLoginResDto struct {
+	User      string `json:"UserName"`
+	AuthToken string `json:"AuthToken"`
+}
+
+type SsoLoginData struct {
+	Expiration     time.Time `json:"expiration"`
+	OauthProvider  string    `json:"oauthprovider,omitempty"`
+	OauthCode      string    `json:"oauthcode,omitempty"`
+	Username       string    `json:"username,omitempty"`
+	AmbAccessToken string    `json:"ambaccesstoken,omitempty"`
+}
+
+type LoginReqDto struct {
+	Email    string `json:"email"`
+	TenantID string `json:"tenant_id"`
+}
+
+const (
+	ResHeaderKeyStAccessToken = "St-Access-Token"
+)

+ 26 - 8
mq/handlers.go

@@ -7,6 +7,7 @@ import (
 	mqtt "github.com/eclipse/paho.mqtt.golang"
 	mqtt "github.com/eclipse/paho.mqtt.golang"
 	"github.com/google/uuid"
 	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic/hostactions"
 	"github.com/gravitl/netmaker/logic/hostactions"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
@@ -193,14 +194,8 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
 			return
 			return
 		}
 		}
 		sendPeerUpdate = true
 		sendPeerUpdate = true
-	case models.RegisterWithTurn:
-		if servercfg.IsUsingTurn() {
-			err = logic.RegisterHostWithTurn(hostUpdate.Host.ID.String(), hostUpdate.Host.HostPass)
-			if err != nil {
-				slog.Error("failed to register host with turn server", "id", currentHost.ID, "error", err)
-				return
-			}
-		}
+	case models.SignalHost:
+		signalPeer(hostUpdate.Signal)
 
 
 	}
 	}
 
 
@@ -212,6 +207,29 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
 	}
 	}
 }
 }
 
 
+func signalPeer(signal models.Signal) {
+
+	if signal.ToHostPubKey == "" {
+		msg := "insufficient data to signal peer"
+		logger.Log(0, msg)
+		return
+	}
+	signal.IsPro = servercfg.IsPro
+	peerHost, err := logic.GetHost(signal.ToHostID)
+	if err != nil {
+		slog.Error("failed to signal, peer not found", "error", err)
+		return
+	}
+	err = HostUpdate(&models.HostUpdate{
+		Action: models.SignalHost,
+		Host:   *peerHost,
+		Signal: signal,
+	})
+	if err != nil {
+		slog.Error("failed to publish signal to peer", "error", err)
+	}
+}
+
 // ClientPeerUpdate  message handler -- handles updating peers after signal from client nodes
 // ClientPeerUpdate  message handler -- handles updating peers after signal from client nodes
 func ClientPeerUpdate(client mqtt.Client, msg mqtt.Message) {
 func ClientPeerUpdate(client mqtt.Client, msg mqtt.Message) {
 	id, err := GetID(msg.Topic())
 	id, err := GetID(msg.Topic())

+ 1 - 1
release.md

@@ -1,5 +1,5 @@
 
 
-# Netmaker v0.21.3
+# Netmaker v0.22.0
 
 
 ## Whats New
 ## Whats New
 - Auto Relay via Enrollment key
 - Auto Relay via Enrollment key

+ 0 - 12
scripts/netmaker.default.env

@@ -6,10 +6,6 @@ NM_DOMAIN=
 SERVER_HOST=
 SERVER_HOST=
 # The admin master key for accessing the API. Change this in any production installation.
 # The admin master key for accessing the API. Change this in any production installation.
 MASTER_KEY=
 MASTER_KEY=
-# The username to set for turn api access
-TURN_USERNAME=
-# The password to set for turn api access
-TURN_PASSWORD=
 # The username to set for MQ access
 # The username to set for MQ access
 MQ_USERNAME=
 MQ_USERNAME=
 # The password to set for MQ access
 # The password to set for MQ access
@@ -42,18 +38,10 @@ DATABASE=sqlite
 # If using "host networking", it will find and detect the IP of the mq container.
 # If using "host networking", it will find and detect the IP of the mq container.
 # For EMQX websockets use `SERVER_BROKER_ENDPOINT=ws://mq:8083/mqtt`
 # For EMQX websockets use `SERVER_BROKER_ENDPOINT=ws://mq:8083/mqtt`
 SERVER_BROKER_ENDPOINT=ws://mq:1883 
 SERVER_BROKER_ENDPOINT=ws://mq:1883 
-# The reachable port of STUN on the server
-STUN_PORT=3478
 # Logging verbosity level - 1, 2, or 3
 # Logging verbosity level - 1, 2, or 3
 VERBOSITY=1
 VERBOSITY=1
-# Port to access turn server
-TURN_PORT=3479
-# Config for using turn, accepts either true/false
-USE_TURN=true
 DEBUG_MODE=off
 DEBUG_MODE=off
-TURN_API_PORT=8089
 # Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST).
 # Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST).
-# Change to "off" to turn off.
 REST_BACKEND=on
 REST_BACKEND=on
 # If turned "on", Server will not set Host based on remote IP check.
 # If turned "on", Server will not set Host based on remote IP check.
 # This is already overridden if SERVER_HOST is set. Turned "off" by default.
 # This is already overridden if SERVER_HOST is set. Turned "off" by default.

+ 3 - 55
scripts/nm-quick.sh

@@ -305,11 +305,10 @@ save_config() { (
 		save_config_item SERVER_IMAGE_TAG "$IMAGE_TAG"
 		save_config_item SERVER_IMAGE_TAG "$IMAGE_TAG"
 	fi
 	fi
 	# copy entries from the previous config
 	# copy entries from the previous config
-	local toCopy=("SERVER_HOST" "MASTER_KEY" "TURN_USERNAME" "TURN_PASSWORD" "MQ_USERNAME" "MQ_PASSWORD"
+	local toCopy=("SERVER_HOST" "MASTER_KEY" "MQ_USERNAME" "MQ_PASSWORD"
 		"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT"
 		"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT"
-		"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "STUN_PORT" "VERBOSITY"
-		"TURN_PORT" "USE_TURN" "DEBUG_MODE" "TURN_API_PORT" "REST_BACKEND"
-		"DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
+		"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "VERBOSITY"
+		"DEBUG_MODE"  "REST_BACKEND" "DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
 		"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT" "JWT_VALIDITY_DURATION" "RAC_AUTO_DISABLE")
 		"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT" "JWT_VALIDITY_DURATION" "RAC_AUTO_DISABLE")
 	for name in "${toCopy[@]}"; do
 	for name in "${toCopy[@]}"; do
 		save_config_item $name "${!name}"
 		save_config_item $name "${!name}"
@@ -550,8 +549,6 @@ set_install_vars() {
 	echo "          dashboard.$NETMAKER_BASE_DOMAIN"
 	echo "          dashboard.$NETMAKER_BASE_DOMAIN"
 	echo "                api.$NETMAKER_BASE_DOMAIN"
 	echo "                api.$NETMAKER_BASE_DOMAIN"
 	echo "             broker.$NETMAKER_BASE_DOMAIN"
 	echo "             broker.$NETMAKER_BASE_DOMAIN"
-	echo "               turn.$NETMAKER_BASE_DOMAIN"
-	echo "            turnapi.$NETMAKER_BASE_DOMAIN"
 
 
 	if [ "$INSTALL_TYPE" = "pro" ]; then
 	if [ "$INSTALL_TYPE" = "pro" ]; then
 		echo "         prometheus.$NETMAKER_BASE_DOMAIN"
 		echo "         prometheus.$NETMAKER_BASE_DOMAIN"
@@ -657,55 +654,6 @@ set_install_vars() {
 		done
 		done
 	fi
 	fi
 
 
-	unset GET_TURN_USERNAME
-	unset GET_TURN_PASSWORD
-	unset CONFIRM_TURN_PASSWORD
-	echo "Enter Credentials For TURN..."
-	if [ -z $AUTO_BUILD ]; then
-		read -p "TURN Username (click 'enter' to use 'netmaker'): " GET_TURN_USERNAME
-	fi
-	if [ -z "$GET_TURN_USERNAME" ]; then
-		echo "using default username for TURN"
-		TURN_USERNAME="netmaker"
-	else
-		TURN_USERNAME="$GET_TURN_USERNAME"
-	fi
-
-	if test -z "$TURN_PASSWORD"; then
-		TURN_PASSWORD=$(
-			tr -dc A-Za-z0-9 </dev/urandom | head -c 30
-			echo ''
-		)
-	fi
-
-	if [ -z $AUTO_BUILD ]; then
-		select domain_option in "Auto Generated / Config Password" "Input Your Own Password"; do
-			case $REPLY in
-			1)
-				echo "using random password for turn"
-				break
-				;;
-			2)
-				while true; do
-					echo "Enter your Password For TURN: "
-					read -s GET_TURN_PASSWORD
-					echo "Enter your password again to confirm: "
-					read -s CONFIRM_TURN_PASSWORD
-					if [ ${GET_TURN_PASSWORD} != ${CONFIRM_TURN_PASSWORD} ]; then
-						echo "wrong password entered, try again..."
-						continue
-					fi
-					TURN_PASSWORD="$GET_TURN_PASSWORD"
-					echo "TURN Password Saved Successfully!!"
-					break
-				done
-				break
-				;;
-			*) echo "invalid option $REPLY" ;;
-			esac
-		done
-	fi
-
 	wait_seconds 2
 	wait_seconds 2
 
 
 	echo "-----------------------------------------------------------------"
 	echo "-----------------------------------------------------------------"

+ 1 - 1
scripts/nm-upgrade-0-17-1-to-0-19-0.sh

@@ -1,6 +1,6 @@
 #!/bin/bash
 #!/bin/bash
 
 
-LATEST="v0.21.3"
+LATEST="v0.21.0"
 INSTALL_PATH="/root"
 INSTALL_PATH="/root"
 
 
 trap restore_old_netmaker_instructions
 trap restore_old_netmaker_instructions

+ 0 - 2
scripts/nm-upgrade.sh

@@ -356,8 +356,6 @@ set_install_vars() {
 	echo "          dashboard.$NETMAKER_BASE_DOMAIN"
 	echo "          dashboard.$NETMAKER_BASE_DOMAIN"
 	echo "                api.$NETMAKER_BASE_DOMAIN"
 	echo "                api.$NETMAKER_BASE_DOMAIN"
 	echo "             broker.$NETMAKER_BASE_DOMAIN"
 	echo "             broker.$NETMAKER_BASE_DOMAIN"
-	echo "               turn.$NETMAKER_BASE_DOMAIN"
-	echo "            turnapi.$NETMAKER_BASE_DOMAIN"
 
 
 	if [ "$INSTALL_TYPE" = "pro" ]; then
 	if [ "$INSTALL_TYPE" = "pro" ]; then
 		echo "         prometheus.$NETMAKER_BASE_DOMAIN"
 		echo "         prometheus.$NETMAKER_BASE_DOMAIN"

+ 0 - 89
servercfg/serverconf.go

@@ -45,7 +45,6 @@ func GetServerConfig() config.ServerConfig {
 	cfg.AllowedOrigin = GetAllowedOrigin()
 	cfg.AllowedOrigin = GetAllowedOrigin()
 	cfg.RestBackend = "off"
 	cfg.RestBackend = "off"
 	cfg.NodeID = GetNodeID()
 	cfg.NodeID = GetNodeID()
-	cfg.StunPort = GetStunPort()
 	cfg.BrokerType = GetBrokerType()
 	cfg.BrokerType = GetBrokerType()
 	cfg.EmqxRestEndpoint = GetEmqxRestEndpoint()
 	cfg.EmqxRestEndpoint = GetEmqxRestEndpoint()
 	if AutoUpdateEnabled() {
 	if AutoUpdateEnabled() {
@@ -125,45 +124,9 @@ func GetServerInfo() models.ServerConfig {
 	}
 	}
 	cfg.Version = GetVersion()
 	cfg.Version = GetVersion()
 	cfg.IsPro = IsPro
 	cfg.IsPro = IsPro
-	cfg.StunPort = GetStunPort()
-	cfg.TurnDomain = GetTurnHost()
-	cfg.TurnPort = GetTurnPort()
-	cfg.UseTurn = IsUsingTurn()
 	return cfg
 	return cfg
 }
 }
 
 
-// GetTurnHost - fetches the turn host domain
-func GetTurnHost() string {
-	turnServer := ""
-	if os.Getenv("TURN_SERVER_HOST") != "" {
-		turnServer = os.Getenv("TURN_SERVER_HOST")
-	} else if config.Config.Server.TurnServer != "" {
-		turnServer = config.Config.Server.TurnServer
-	}
-	return turnServer
-}
-
-// IsUsingTurn - check if server has turn configured
-func IsUsingTurn() (b bool) {
-	if os.Getenv("USE_TURN") != "" {
-		b = os.Getenv("USE_TURN") == "true"
-	} else {
-		b = config.Config.Server.UseTurn
-	}
-	return
-}
-
-// GetTurnApiHost - fetches the turn api host domain
-func GetTurnApiHost() string {
-	turnApiServer := ""
-	if os.Getenv("TURN_SERVER_API_HOST") != "" {
-		turnApiServer = os.Getenv("TURN_SERVER_API_HOST")
-	} else if config.Config.Server.TurnApiServer != "" {
-		turnApiServer = config.Config.Server.TurnApiServer
-	}
-	return turnApiServer
-}
-
 // GetFrontendURL - gets the frontend url
 // GetFrontendURL - gets the frontend url
 func GetFrontendURL() string {
 func GetFrontendURL() string {
 	var frontend = ""
 	var frontend = ""
@@ -646,58 +609,6 @@ func GetNetmakerTenantID() string {
 	return netmakerTenantID
 	return netmakerTenantID
 }
 }
 
 
-// GetStunPort - Get the port to run the stun server on
-func GetStunPort() int {
-	port := 3478 //default
-	if os.Getenv("STUN_PORT") != "" {
-		portInt, err := strconv.Atoi(os.Getenv("STUN_PORT"))
-		if err == nil {
-			port = portInt
-		}
-	} else if config.Config.Server.StunPort != 0 {
-		port = config.Config.Server.StunPort
-	}
-	return port
-}
-
-// GetTurnPort - Get the port to run the turn server on
-func GetTurnPort() int {
-	port := 3479 //default
-	if os.Getenv("TURN_PORT") != "" {
-		portInt, err := strconv.Atoi(os.Getenv("TURN_PORT"))
-		if err == nil {
-			port = portInt
-		}
-	} else if config.Config.Server.TurnPort != 0 {
-		port = config.Config.Server.TurnPort
-	}
-	return port
-}
-
-// GetTurnUserName - fetches the turn server username
-func GetTurnUserName() string {
-	userName := ""
-	if os.Getenv("TURN_USERNAME") != "" {
-		userName = os.Getenv("TURN_USERNAME")
-	} else {
-		userName = config.Config.Server.TurnUserName
-	}
-	return userName
-
-}
-
-// GetTurnPassword - fetches the turn server password
-func GetTurnPassword() string {
-	pass := ""
-	if os.Getenv("TURN_PASSWORD") != "" {
-		pass = os.Getenv("TURN_PASSWORD")
-	} else {
-		pass = config.Config.Server.TurnPassword
-	}
-	return pass
-
-}
-
 // GetNetworkLimit - fetches free tier limits on users
 // GetNetworkLimit - fetches free tier limits on users
 func GetUserLimit() int {
 func GetUserLimit() int {
 	var userslimit int
 	var userslimit int

+ 1 - 1
swagger.yml

@@ -1149,7 +1149,7 @@ info:
 
 
         API calls must be authenticated via a header of the format -H “Authorization: Bearer <YOUR_SECRET_KEY>” There are two methods to obtain YOUR_SECRET_KEY: 1. Using the masterkey. By default, this value is “secret key,” but you should change this on your instance and keep it secure. This value can be set via env var at startup or in a config file (config/environments/< env >.yaml). See the [Netmaker](https://docs.netmaker.org/index.html) documentation for more details. 2. Using a JWT received for a node. This can be retrieved by calling the /api/nodes/<network>/authenticate endpoint, as documented below.
         API calls must be authenticated via a header of the format -H “Authorization: Bearer <YOUR_SECRET_KEY>” There are two methods to obtain YOUR_SECRET_KEY: 1. Using the masterkey. By default, this value is “secret key,” but you should change this on your instance and keep it secure. This value can be set via env var at startup or in a config file (config/environments/< env >.yaml). See the [Netmaker](https://docs.netmaker.org/index.html) documentation for more details. 2. Using a JWT received for a node. This can be retrieved by calling the /api/nodes/<network>/authenticate endpoint, as documented below.
     title: Netmaker
     title: Netmaker
-    version: 0.21.3
+    version: 0.22.0
 paths:
 paths:
     /api/dns:
     /api/dns:
         get:
         get: