NET-1950: Persist Server Settings in the DB (#3419)

* feat: api access tokens

* revoke all user tokens

* redefine access token api routes, add auto egress option to enrollment keys

* add server settings apis, add db table for settigs

* handle server settings updates

* switch to using settings from DB

* fix sever settings migration

* revet force migration for settings

* fix server settings database write

* fix revoked tokens to be unauthorized

* remove unused functions

* convert access token to sql schema

* switch access token to sql schema

* fix merge conflicts

* fix server settings types

* bypass basic auth setting for super admin

* add TODO comment

* publish peer update on settings update

* chore(go): import style changes from migration branch;

1. Singular file names for table schema.
2. No table name method.
3. Use .Model instead of .Table.
4. No unnecessary tagging.

* remove nat check on egress gateway request

* Revert "remove nat check on egress gateway request"

This reverts commit 0aff12a189.

* feat(go): add db middleware;

* feat(go): restore method;

* feat(go): add user access token schema;

* fix user auth api:

* re initalise oauth and email config

* set verbosity

* sync auto update settings with hosts

* sync auto update settings with hosts

* mask secret and convert jwt duration to minutes

* convert jwt duration to minutes

* notify peers after settings update

* compare with curr settings before updating

* send host update to devices on auto update

---------

Co-authored-by: Vishal Dalwadi <dalwadivishal26@gmail.com>
This commit is contained in:
Abhishek K
2025-04-30 02:34:10 +04:00
committed by GitHub
parent 262803c234
commit 309e4795a1
34 changed files with 561 additions and 134 deletions

View File

@@ -67,7 +67,7 @@ func SessionHandler(conn *websocket.Conn) {
if len(registerMessage.User) > 0 { // handle basic auth if len(registerMessage.User) > 0 { // handle basic auth
logger.Log(0, "user registration attempted with host:", registerMessage.RegisterHost.Name, "user:", registerMessage.User) logger.Log(0, "user registration attempted with host:", registerMessage.RegisterHost.Name, "user:", registerMessage.User)
if !servercfg.IsBasicAuthEnabled() { if !logic.IsBasicAuthEnabled() {
err = conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) err = conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil { if err != nil {
logger.Log(0, "error during message writing:", err.Error()) logger.Log(0, "error during message writing:", err.Error())
@@ -207,7 +207,7 @@ func SessionHandler(conn *websocket.Conn) {
netsToAdd = append(netsToAdd, newNet) netsToAdd = append(netsToAdd, newNet)
} }
} }
server := servercfg.GetServerInfo() server := logic.GetServerInfo()
server.TrafficKey = key server.TrafficKey = key
result.Host.HostPass = "" result.Host.HostPass = ""
response := models.RegisterResponse{ response := models.RegisterResponse{

View File

@@ -75,7 +75,6 @@ type ServerConfig struct {
NetmakerTenantID string `yaml:"netmaker_tenant_id"` NetmakerTenantID string `yaml:"netmaker_tenant_id"`
IsPro string `yaml:"is_ee" json:"IsEE"` IsPro string `yaml:"is_ee" json:"IsEE"`
StunPort int `yaml:"stun_port"` StunPort int `yaml:"stun_port"`
StunList string `yaml:"stun_list"`
TurnServer string `yaml:"turn_server"` TurnServer string `yaml:"turn_server"`
TurnApiServer string `yaml:"turn_api_server"` TurnApiServer string `yaml:"turn_api_server"`
TurnPort int `yaml:"turn_port"` TurnPort int `yaml:"turn_port"`

View File

@@ -3,6 +3,7 @@ package controller
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/gravitl/netmaker/db"
"net/http" "net/http"
"os" "os"
"strings" "strings"
@@ -18,6 +19,7 @@ import (
// HttpMiddlewares - middleware functions for REST interactions // HttpMiddlewares - middleware functions for REST interactions
var HttpMiddlewares = []mux.MiddlewareFunc{ var HttpMiddlewares = []mux.MiddlewareFunc{
db.Middleware,
userMiddleWare, userMiddleWare,
} }

View File

@@ -164,9 +164,9 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
return return
} }
// check if default domain is appended if not append // check if default domain is appended if not append
if servercfg.GetDefaultDomain() != "" && if logic.GetDefaultDomain() != "" &&
!strings.HasSuffix(entry.Name, servercfg.GetDefaultDomain()) { !strings.HasSuffix(entry.Name, logic.GetDefaultDomain()) {
entry.Name += "." + servercfg.GetDefaultDomain() entry.Name += "." + logic.GetDefaultDomain()
} }
entry, err = logic.CreateDNS(entry) entry, err = logic.CreateDNS(entry)
if err != nil { if err != nil {
@@ -185,7 +185,7 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
} }
} }
if servercfg.GetManageDNS() { if logic.GetManageDNS() {
mq.SendDNSSyncByNetwork(netID) mq.SendDNSSyncByNetwork(netID)
} }
@@ -230,7 +230,7 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) {
} }
} }
if servercfg.GetManageDNS() { if logic.GetManageDNS() {
mq.SendDNSSyncByNetwork(netID) mq.SendDNSSyncByNetwork(netID)
} }
@@ -293,7 +293,7 @@ func pushDNS(w http.ResponseWriter, r *http.Request) {
func syncDNS(w http.ResponseWriter, r *http.Request) { func syncDNS(w http.ResponseWriter, r *http.Request) {
// Set header // Set header
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if !servercfg.GetManageDNS() { if !logic.GetManageDNS() {
logic.ReturnErrorResponse( logic.ReturnErrorResponse(
w, w,
r, r,

View File

@@ -349,7 +349,7 @@ func handleHostRegister(w http.ResponseWriter, r *http.Request) {
} }
} }
// ready the response // ready the response
server := servercfg.GetServerInfo() server := logic.GetServerInfo()
server.TrafficKey = key server.TrafficKey = key
response := models.RegisterResponse{ response := models.RegisterResponse{
ServerConf: server, ServerConf: server,

View File

@@ -209,7 +209,7 @@ func pull(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
serverConf := servercfg.GetServerInfo() serverConf := logic.GetServerInfo()
key, keyErr := logic.RetrievePublicTrafficKey() key, keyErr := logic.RetrievePublicTrafficKey()
if keyErr != nil { if keyErr != nil {
logger.Log(0, "error retrieving key:", keyErr.Error()) logger.Log(0, "error retrieving key:", keyErr.Error())
@@ -230,7 +230,7 @@ func pull(w http.ResponseWriter, r *http.Request) {
ChangeDefaultGw: hPU.ChangeDefaultGw, ChangeDefaultGw: hPU.ChangeDefaultGw,
DefaultGwIp: hPU.DefaultGwIp, DefaultGwIp: hPU.DefaultGwIp,
IsInternetGw: hPU.IsInternetGw, IsInternetGw: hPU.IsInternetGw,
EndpointDetection: servercfg.IsEndpointDetectionEnabled(), EndpointDetection: logic.IsEndpointDetectionEnabled(),
} }
logger.Log(1, hostID, "completed a pull") logger.Log(1, hostID, "completed a pull")

View File

@@ -70,7 +70,7 @@ func migrate(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return return
} }
server = servercfg.GetServerInfo() server = logic.GetServerInfo()
key, keyErr := logic.RetrievePublicTrafficKey() key, keyErr := logic.RetrievePublicTrafficKey()
if keyErr != nil { if keyErr != nil {
slog.Error("retrieving traffickey", "error", err) slog.Error("retrieving traffickey", "error", err)
@@ -134,7 +134,7 @@ func convertLegacyHostNode(legacy models.LegacyNode) (models.Host, models.Node)
host := models.Host{} host := models.Host{}
host.ID = uuid.New() host.ID = uuid.New()
host.IPForwarding = models.ParseBool(legacy.IPForwarding) host.IPForwarding = models.ParseBool(legacy.IPForwarding)
host.AutoUpdate = servercfg.AutoUpdateEnabled() host.AutoUpdate = logic.AutoUpdateEnabled()
host.Interface = "netmaker" host.Interface = "netmaker"
host.ListenPort = int(legacy.ListenPort) host.ListenPort = int(legacy.ListenPort)
if host.ListenPort == 0 { if host.ListenPort == 0 {

View File

@@ -588,8 +588,7 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(network.NetID)) logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(network.NetID))
logic.CreateDefaultAclNetworkPolicies(models.NetworkID(network.NetID)) logic.CreateDefaultAclNetworkPolicies(models.NetworkID(network.NetID))
logic.CreateDefaultTags(models.NetworkID(network.NetID)) logic.CreateDefaultTags(models.NetworkID(network.NetID))
logic.AddNetworkToAllocatedIpMap(network.NetID)
go logic.AddNetworkToAllocatedIpMap(network.NetID)
go func() { go func() {
defaultHosts := logic.GetDefaultHosts() defaultHosts := logic.GetDefaultHosts()

View File

@@ -477,7 +477,7 @@ func getNode(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
server := servercfg.GetServerInfo() server := logic.GetServerInfo()
response := models.NodeGet{ response := models.NodeGet{
Node: node, Node: node,
Host: *host, Host: *host,

View File

@@ -2,6 +2,7 @@ package controller
import ( import (
"encoding/json" "encoding/json"
"errors"
"net/http" "net/http"
"os" "os"
"strings" "strings"
@@ -12,6 +13,7 @@ import (
"golang.org/x/exp/slog" "golang.org/x/exp/slog"
"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/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/mq" "github.com/gravitl/netmaker/mq"
@@ -41,6 +43,10 @@ func serverHandlers(r *mux.Router) {
).Methods(http.MethodPost) ).Methods(http.MethodPost)
r.HandleFunc("/api/server/getconfig", allowUsers(http.HandlerFunc(getConfig))). r.HandleFunc("/api/server/getconfig", allowUsers(http.HandlerFunc(getConfig))).
Methods(http.MethodGet) Methods(http.MethodGet)
r.HandleFunc("/api/server/settings", allowUsers(http.HandlerFunc(getSettings))).
Methods(http.MethodGet)
r.HandleFunc("/api/server/settings", logic.SecurityCheck(true, http.HandlerFunc(updateSettings))).
Methods(http.MethodPut)
r.HandleFunc("/api/server/getserverinfo", logic.SecurityCheck(true, http.HandlerFunc(getServerInfo))). r.HandleFunc("/api/server/getserverinfo", logic.SecurityCheck(true, http.HandlerFunc(getServerInfo))).
Methods(http.MethodGet) Methods(http.MethodGet)
r.HandleFunc("/api/server/status", getStatus).Methods(http.MethodGet) r.HandleFunc("/api/server/status", getStatus).Methods(http.MethodGet)
@@ -207,7 +213,7 @@ func getServerInfo(w http.ResponseWriter, r *http.Request) {
// get params // get params
json.NewEncoder(w).Encode(servercfg.GetServerInfo()) json.NewEncoder(w).Encode(logic.GetServerInfo())
// w.WriteHeader(http.StatusOK) // w.WriteHeader(http.StatusOK)
} }
@@ -222,7 +228,7 @@ func getConfig(w http.ResponseWriter, r *http.Request) {
// get params // get params
scfg := servercfg.GetServerConfig() scfg := logic.GetServerConfig()
scfg.IsPro = "no" scfg.IsPro = "no"
if servercfg.IsPro { if servercfg.IsPro {
scfg.IsPro = "yes" scfg.IsPro = "yes"
@@ -230,3 +236,66 @@ func getConfig(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(scfg) json.NewEncoder(w).Encode(scfg)
// w.WriteHeader(http.StatusOK) // w.WriteHeader(http.StatusOK)
} }
// @Summary Get the server settings
// @Router /api/server/settings [get]
// @Tags Server
// @Security oauth2
// @Success 200 {object} config.ServerSettings
func getSettings(w http.ResponseWriter, r *http.Request) {
scfg := logic.GetServerSettings()
scfg.ClientSecret = logic.Mask()
logic.ReturnSuccessResponseWithJson(w, r, scfg, "fetched server settings successfully")
}
// @Summary Update the server settings
// @Router /api/server/settings [put]
// @Tags Server
// @Security oauth2
// @Success 200 {object} config.ServerSettings
func updateSettings(w http.ResponseWriter, r *http.Request) {
var req models.ServerSettings
force := r.URL.Query().Get("force")
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
if !logic.ValidateNewSettings(req) {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid settings"), "badrequest"))
return
}
currSettings := logic.GetServerSettings()
err := logic.UpsertServerSettings(req)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to udpate server settings "+err.Error()), "internal"))
return
}
go reInit(currSettings, req, force == "true")
logic.ReturnSuccessResponseWithJson(w, r, req, "updated server settings successfully")
}
func reInit(curr, new models.ServerSettings, force bool) {
logic.SettingsMutex.Lock()
defer logic.SettingsMutex.Unlock()
logic.InitializeAuthProvider()
logic.EmailInit()
logic.SetVerbosity(int(logic.GetServerSettings().Verbosity))
// check if auto update is changed
if force {
if curr.NetclientAutoUpdate != new.NetclientAutoUpdate {
// update all hosts
hosts, _ := logic.GetAllHosts()
for _, host := range hosts {
host.AutoUpdate = new.NetclientAutoUpdate
logic.UpsertHost(&host)
mq.HostUpdate(&models.HostUpdate{
Action: models.UpdateHost,
Host: host,
})
}
}
}
go mq.PublishPeerUpdate(false)
}

View File

@@ -217,16 +217,6 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
var errorResponse = models.ErrorResponse{ var errorResponse = models.ErrorResponse{
Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
} }
if !servercfg.IsBasicAuthEnabled() {
logic.ReturnErrorResponse(
response,
request,
logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
)
return
}
decoder := json.NewDecoder(request.Body) decoder := json.NewDecoder(request.Body)
decoderErr := decoder.Decode(&authRequest) decoderErr := decoder.Decode(&authRequest)
defer request.Body.Close() defer request.Body.Close()
@@ -236,15 +226,29 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
logic.ReturnErrorResponse(response, request, errorResponse) logic.ReturnErrorResponse(response, request, errorResponse)
return return
} }
user, err := logic.GetUser(authRequest.UserName)
if err != nil {
logger.Log(0, authRequest.UserName, "user validation failed: ",
err.Error())
logic.ReturnErrorResponse(response, request, logic.FormatError(err, "unauthorized"))
return
}
if logic.IsOauthUser(user) == nil {
logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("user is registered via SSO"), "badrequest"))
return
}
if !user.IsSuperAdmin && !logic.IsBasicAuthEnabled() {
logic.ReturnErrorResponse(
response,
request,
logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
)
return
}
if val := request.Header.Get("From-Ui"); val == "true" { if val := request.Header.Get("From-Ui"); val == "true" {
// request came from UI, if normal user block Login // request came from UI, if normal user block Login
user, err := logic.GetUser(authRequest.UserName)
if err != nil {
logger.Log(0, authRequest.UserName, "user validation failed: ",
err.Error())
logic.ReturnErrorResponse(response, request, logic.FormatError(err, "unauthorized"))
return
}
role, err := logic.GetRole(user.PlatformRoleID) role, err := logic.GetRole(user.PlatformRoleID)
if err != nil { if err != nil {
logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("access denied to dashboard"), "unauthorized")) logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("access denied to dashboard"), "unauthorized"))
@@ -255,15 +259,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
return return
} }
} }
user, err := logic.GetUser(authRequest.UserName)
if err != nil {
logic.ReturnErrorResponse(response, request, logic.FormatError(err, "unauthorized"))
return
}
if logic.IsOauthUser(user) == nil {
logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("user is registered via SSO"), "badrequest"))
return
}
username := authRequest.UserName username := authRequest.UserName
jwt, err := logic.VerifyAuthRequest(authRequest) jwt, err := logic.VerifyAuthRequest(authRequest)
if err != nil { if err != nil {
@@ -305,7 +301,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
response.Write(successJSONResponse) response.Write(successJSONResponse)
go func() { go func() {
if servercfg.IsPro && servercfg.GetRacAutoDisable() { if servercfg.IsPro && logic.GetRacAutoDisable() {
// enable all associeated clients for the user // enable all associeated clients for the user
clients, err := logic.GetAllExtClients() clients, err := logic.GetAllExtClients()
if err != nil { if err != nil {
@@ -479,7 +475,7 @@ func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
return return
} }
if !servercfg.IsBasicAuthEnabled() { if !logic.IsBasicAuthEnabled() {
logic.ReturnErrorResponse( logic.ReturnErrorResponse(
w, w,
r, r,
@@ -527,7 +523,7 @@ func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only admins can be promoted to superadmin role"), "forbidden")) logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only admins can be promoted to superadmin role"), "forbidden"))
return return
} }
if !servercfg.IsBasicAuthEnabled() { if !logic.IsBasicAuthEnabled() {
logic.ReturnErrorResponse( logic.ReturnErrorResponse(
w, w,
r, r,

View File

@@ -69,6 +69,8 @@ const (
TAG_TABLE_NAME = "tags" TAG_TABLE_NAME = "tags"
// PEER_ACK_TABLE - table for failover peer ack // PEER_ACK_TABLE - table for failover peer ack
PEER_ACK_TABLE = "peer_ack" PEER_ACK_TABLE = "peer_ack"
// SERVER_SETTINGS - table for server settings
SERVER_SETTINGS = "server_settings"
// == ERROR CONSTS == // == ERROR CONSTS ==
// NO_RECORD - no singular result found // NO_RECORD - no singular result found
NO_RECORD = "no result found" NO_RECORD = "no result found"
@@ -125,7 +127,7 @@ var Tables = []string{
TAG_TABLE_NAME, TAG_TABLE_NAME,
ACLS_TABLE_NAME, ACLS_TABLE_NAME,
PEER_ACK_TABLE, PEER_ACK_TABLE,
// ACCESS_TOKENS_TABLE_NAME, SERVER_SETTINGS,
} }
func getCurrentDB() map[string]interface{} { func getCurrentDB() map[string]interface{} {

7
go.mod
View File

@@ -48,6 +48,9 @@ require (
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/spf13/cobra v1.8.1 github.com/spf13/cobra v1.8.1
gopkg.in/mail.v2 v2.3.1 gopkg.in/mail.v2 v2.3.1
gorm.io/driver/postgres v1.5.11
gorm.io/driver/sqlite v1.5.7
gorm.io/gorm v1.25.12
) )
require ( require (
@@ -63,12 +66,10 @@ require (
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/seancfoley/bintree v1.3.1 // indirect github.com/seancfoley/bintree v1.3.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gorm.io/driver/postgres v1.5.11 // indirect
gorm.io/driver/sqlite v1.5.7 // indirect
gorm.io/gorm v1.25.12 // indirect
) )
require ( require (

17
go.sum
View File

@@ -61,9 +61,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
@@ -89,6 +88,8 @@ github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rqlite/gorqlite v0.0.0-20240122221808-a8a425b1a6aa h1:hxMLFbj+F444JAS5nUQxTDZwUxwCRqg3WkNqhiDzXrM= 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/rqlite/gorqlite v0.0.0-20240122221808-a8a425b1a6aa/go.mod h1:xF/KoXmrRyahPfo5L7Szb5cAAUl53dMWBh9cMruGEZg=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -115,8 +116,6 @@ go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwE
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 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.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.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
@@ -135,8 +134,6 @@ golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -147,8 +144,6 @@ 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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.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.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -162,8 +157,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -176,8 +169,8 @@ golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb/go.mod h1:m
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk=
gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -31,6 +31,8 @@ func ClearSuperUserCache() {
superUser = models.User{} superUser = models.User{}
} }
var InitializeAuthProvider = func() string { return "" }
// HasSuperAdmin - checks if server has an superadmin/owner // HasSuperAdmin - checks if server has an superadmin/owner
func HasSuperAdmin() (bool, error) { func HasSuperAdmin() (bool, error) {

View File

@@ -12,7 +12,6 @@ import (
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg"
"github.com/txn2/txeh" "github.com/txn2/txeh"
) )
@@ -106,7 +105,7 @@ func GetNodeDNS(network string) ([]models.DNSEntry, error) {
if err != nil { if err != nil {
return dns, err return dns, err
} }
defaultDomain := servercfg.GetDefaultDomain() defaultDomain := GetDefaultDomain()
for _, node := range nodes { for _, node := range nodes {
if node.Network != network { if node.Network != network {
continue continue

View File

@@ -228,7 +228,7 @@ func CreateHost(h *models.Host) error {
return err return err
} }
h.HostPass = string(hash) h.HostPass = string(hash)
h.AutoUpdate = servercfg.AutoUpdateEnabled() h.AutoUpdate = AutoUpdateEnabled()
checkForZombieHosts(h) checkForZombieHosts(h)
return UpsertHost(h) return UpsertHost(h)
} }

View File

@@ -61,8 +61,8 @@ func CreateUserAccessJwtToken(username string, role models.UserRoleID, d time.Ti
UserName: username, UserName: username,
Role: role, Role: role,
TokenType: models.AccessTokenType, TokenType: models.AccessTokenType,
Api: servercfg.ServerInfo.APIHost, Api: servercfg.GetAPIHost(),
RacAutoDisable: servercfg.GetRacAutoDisable() && (role != models.SuperAdminRole && role != models.AdminRole), RacAutoDisable: GetRacAutoDisable() && (role != models.SuperAdminRole && role != models.AdminRole),
RegisteredClaims: jwt.RegisteredClaims{ RegisteredClaims: jwt.RegisteredClaims{
Issuer: "Netmaker", Issuer: "Netmaker",
Subject: fmt.Sprintf("user|%s", username), Subject: fmt.Sprintf("user|%s", username),
@@ -82,12 +82,13 @@ func CreateUserAccessJwtToken(username string, role models.UserRoleID, d time.Ti
// CreateUserJWT - creates a user jwt token // CreateUserJWT - creates a user jwt token
func CreateUserJWT(username string, role models.UserRoleID) (response string, err error) { func CreateUserJWT(username string, role models.UserRoleID) (response string, err error) {
expirationTime := time.Now().Add(servercfg.GetServerConfig().JwtValidityDuration) settings := GetServerSettings()
expirationTime := time.Now().Add(time.Duration(settings.JwtValidityDuration) * time.Minute)
claims := &models.UserClaims{ claims := &models.UserClaims{
UserName: username, UserName: username,
Role: role, Role: role,
TokenType: models.UserIDTokenType, TokenType: models.UserIDTokenType,
RacAutoDisable: servercfg.GetRacAutoDisable() && (role != models.SuperAdminRole && role != models.AdminRole), RacAutoDisable: settings.RacAutoDisable && (role != models.SuperAdminRole && role != models.AdminRole),
RegisteredClaims: jwt.RegisteredClaims{ RegisteredClaims: jwt.RegisteredClaims{
Issuer: "Netmaker", Issuer: "Netmaker",
Subject: fmt.Sprintf("user|%s", username), Subject: fmt.Sprintf("user|%s", username),

View File

@@ -157,7 +157,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
Peers: []wgtypes.PeerConfig{}, Peers: []wgtypes.PeerConfig{},
NodePeers: []wgtypes.PeerConfig{}, NodePeers: []wgtypes.PeerConfig{},
HostNetworkInfo: models.HostInfoMap{}, HostNetworkInfo: models.HostInfoMap{},
ServerConfig: servercfg.ServerInfo, ServerConfig: GetServerInfo(),
} }
defer func() { defer func() {
if !hostPeerUpdate.FwUpdate.AllowAll { if !hostPeerUpdate.FwUpdate.AllowAll {

335
logic/settings.go Normal file
View File

@@ -0,0 +1,335 @@
package logic
import (
"encoding/json"
"os"
"regexp"
"strconv"
"strings"
"sync"
"time"
"github.com/gravitl/netmaker/config"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg"
)
var serverSettingsDBKey = "server_cfg"
var SettingsMutex = &sync.RWMutex{}
func GetServerSettings() (s models.ServerSettings) {
data, err := database.FetchRecord(database.SERVER_SETTINGS, serverSettingsDBKey)
if err != nil {
return
}
json.Unmarshal([]byte(data), &s)
return
}
func UpsertServerSettings(s models.ServerSettings) error {
// get curr settings
currSettings := GetServerSettings()
if s.ClientSecret == Mask() {
s.ClientSecret = currSettings.ClientSecret
}
data, err := json.Marshal(s)
if err != nil {
return err
}
err = database.Insert(serverSettingsDBKey, string(data), database.SERVER_SETTINGS)
if err != nil {
return err
}
return nil
}
func ValidateNewSettings(req models.ServerSettings) bool {
// TODO: add checks for different fields
return true
}
func GetServerSettingsFromEnv() (s models.ServerSettings) {
s = models.ServerSettings{
NetclientAutoUpdate: servercfg.AutoUpdateEnabled(),
Verbosity: servercfg.GetVerbosity(),
AuthProvider: os.Getenv("AUTH_PROVIDER"),
OIDCIssuer: os.Getenv("OIDC_ISSUER"),
ClientID: os.Getenv("CLIENT_ID"),
ClientSecret: os.Getenv("CLIENT_SECRET"),
AzureTenant: servercfg.GetAzureTenant(),
Telemetry: servercfg.Telemetry(),
BasicAuth: servercfg.IsBasicAuthEnabled(),
JwtValidityDuration: servercfg.GetJwtValidityDurationFromEnv() / 60,
RacAutoDisable: servercfg.GetRacAutoDisable(),
RacRestrictToSingleNetwork: servercfg.GetRacRestrictToSingleNetwork(),
EndpointDetection: servercfg.IsEndpointDetectionEnabled(),
AllowedEmailDomains: servercfg.GetAllowedEmailDomains(),
EmailSenderAddr: servercfg.GetSenderEmail(),
EmailSenderUser: servercfg.GetSenderUser(),
EmailSenderPassword: servercfg.GetEmaiSenderPassword(),
SmtpHost: servercfg.GetSmtpHost(),
SmtpPort: servercfg.GetSmtpPort(),
MetricInterval: servercfg.GetMetricInterval(),
MetricsPort: servercfg.GetMetricsPort(),
ManageDNS: servercfg.GetManageDNS(),
DefaultDomain: servercfg.GetDefaultDomain(),
Stun: servercfg.IsStunEnabled(),
StunServers: servercfg.GetStunServers(),
TextSize: "16",
Theme: models.Dark,
ReducedMotion: false,
}
return
}
// GetServerConfig - gets the server config into memory from file or env
func GetServerConfig() config.ServerConfig {
var cfg config.ServerConfig
settings := GetServerSettings()
cfg.APIConnString = servercfg.GetAPIConnString()
cfg.CoreDNSAddr = servercfg.GetCoreDNSAddr()
cfg.APIHost = servercfg.GetAPIHost()
cfg.APIPort = servercfg.GetAPIPort()
cfg.MasterKey = "(hidden)"
cfg.DNSKey = "(hidden)"
cfg.AllowedOrigin = servercfg.GetAllowedOrigin()
cfg.RestBackend = "off"
cfg.NodeID = servercfg.GetNodeID()
cfg.BrokerType = servercfg.GetBrokerType()
cfg.EmqxRestEndpoint = servercfg.GetEmqxRestEndpoint()
if settings.NetclientAutoUpdate {
cfg.NetclientAutoUpdate = "enabled"
} else {
cfg.NetclientAutoUpdate = "disabled"
}
if servercfg.IsRestBackend() {
cfg.RestBackend = "on"
}
cfg.DNSMode = "off"
if servercfg.IsDNSMode() {
cfg.DNSMode = "on"
}
cfg.DisplayKeys = "off"
if servercfg.IsDisplayKeys() {
cfg.DisplayKeys = "on"
}
cfg.DisableRemoteIPCheck = "off"
if servercfg.DisableRemoteIPCheck() {
cfg.DisableRemoteIPCheck = "on"
}
cfg.Database = servercfg.GetDB()
cfg.Platform = servercfg.GetPlatform()
cfg.Version = servercfg.GetVersion()
cfg.PublicIp = servercfg.GetServerHostIP()
// == auth config ==
var authInfo = GetAuthProviderInfo(settings)
cfg.AuthProvider = authInfo[0]
cfg.ClientID = authInfo[1]
cfg.ClientSecret = authInfo[2]
cfg.FrontendURL = servercfg.GetFrontendURL()
cfg.AzureTenant = settings.AzureTenant
cfg.Telemetry = settings.Telemetry
cfg.Server = servercfg.GetServer()
cfg.Verbosity = settings.Verbosity
cfg.IsPro = "no"
if servercfg.IsPro {
cfg.IsPro = "yes"
}
cfg.JwtValidityDuration = time.Duration(settings.JwtValidityDuration) * time.Minute
cfg.RacAutoDisable = settings.RacAutoDisable
cfg.RacRestrictToSingleNetwork = settings.RacRestrictToSingleNetwork
cfg.MetricInterval = settings.MetricInterval
cfg.ManageDNS = settings.ManageDNS
cfg.Stun = settings.Stun
cfg.StunServers = settings.StunServers
cfg.DefaultDomain = settings.DefaultDomain
return cfg
}
// GetServerInfo - gets the server config into memory from file or env
func GetServerInfo() models.ServerConfig {
var cfg models.ServerConfig
serverSettings := GetServerSettings()
cfg.Server = servercfg.GetServer()
if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
cfg.MQUserName = "HOST_ID"
cfg.MQPassword = "HOST_PASS"
} else {
cfg.MQUserName = servercfg.GetMqUserName()
cfg.MQPassword = servercfg.GetMqPassword()
}
cfg.API = servercfg.GetAPIConnString()
cfg.CoreDNSAddr = servercfg.GetCoreDNSAddr()
cfg.APIPort = servercfg.GetAPIPort()
cfg.DNSMode = "off"
cfg.Broker = servercfg.GetPublicBrokerEndpoint()
cfg.BrokerType = servercfg.GetBrokerType()
if servercfg.IsDNSMode() {
cfg.DNSMode = "on"
}
cfg.Version = servercfg.GetVersion()
cfg.IsPro = servercfg.IsPro
cfg.MetricInterval = serverSettings.MetricInterval
cfg.MetricsPort = serverSettings.MetricsPort
cfg.ManageDNS = serverSettings.ManageDNS
cfg.Stun = serverSettings.Stun
cfg.StunServers = serverSettings.StunServers
cfg.DefaultDomain = serverSettings.DefaultDomain
cfg.EndpointDetection = serverSettings.EndpointDetection
return cfg
}
// GetDefaultDomain - get the default domain
func GetDefaultDomain() string {
return GetServerSettings().DefaultDomain
}
func ValidateDomain(domain string) bool {
domainPattern := `[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9][a-zA-Z0-9_-]{0,62})*(\.[a-zA-Z][a-zA-Z0-9]{0,10}){1}`
exp := regexp.MustCompile("^" + domainPattern + "$")
return exp.MatchString(domain)
}
// Telemetry - checks if telemetry data should be sent
func Telemetry() string {
return GetServerSettings().Telemetry
}
// GetJwtValidityDuration - returns the JWT validity duration in minutes
func GetJwtValidityDuration() time.Duration {
return GetServerConfig().JwtValidityDuration
}
// GetRacAutoDisable - returns whether the feature to autodisable RAC is enabled
func GetRacAutoDisable() bool {
return GetServerSettings().RacAutoDisable
}
// GetRacRestrictToSingleNetwork - returns whether the feature to allow simultaneous network connections via RAC is enabled
func GetRacRestrictToSingleNetwork() bool {
return GetServerSettings().RacRestrictToSingleNetwork
}
func GetSmtpHost() string {
return GetServerSettings().SmtpHost
}
func GetSmtpPort() int {
return GetServerSettings().SmtpPort
}
func GetSenderEmail() string {
return GetServerSettings().EmailSenderAddr
}
func GetSenderUser() string {
return GetServerSettings().EmailSenderUser
}
func GetEmaiSenderPassword() string {
return GetServerSettings().EmailSenderPassword
}
// AutoUpdateEnabled returns a boolean indicating whether netclient auto update is enabled or disabled
// default is enabled
func AutoUpdateEnabled() bool {
return GetServerSettings().NetclientAutoUpdate
}
// GetAuthProviderInfo = gets the oauth provider info
func GetAuthProviderInfo(settings models.ServerSettings) (pi []string) {
var authProvider = ""
defer func() {
if authProvider == "oidc" {
if settings.OIDCIssuer != "" {
pi = append(pi, settings.OIDCIssuer)
} else {
pi = []string{"", "", ""}
}
}
}()
if settings.AuthProvider != "" && settings.ClientID != "" && settings.ClientSecret != "" {
authProvider = strings.ToLower(settings.AuthProvider)
if authProvider == "google" || authProvider == "azure-ad" || authProvider == "github" || authProvider == "oidc" {
return []string{authProvider, settings.ClientID, settings.ClientSecret}
} else {
authProvider = ""
}
}
return []string{"", "", ""}
}
// GetAzureTenant - retrieve the azure tenant ID from env variable or config file
func GetAzureTenant() string {
return GetServerSettings().AzureTenant
}
// GetMetricsPort - get metrics port
func GetMetricsPort() int {
return GetServerSettings().MetricsPort
}
// GetMetricInterval - get the publish metric interval
func GetMetricIntervalInMinutes() time.Duration {
//default 15 minutes
mi := "15"
if os.Getenv("PUBLISH_METRIC_INTERVAL") != "" {
mi = os.Getenv("PUBLISH_METRIC_INTERVAL")
}
interval, err := strconv.Atoi(mi)
if err != nil {
interval = 15
}
return time.Duration(interval) * time.Minute
}
// GetMetricInterval - get the publish metric interval
func GetMetricInterval() string {
return GetServerSettings().MetricInterval
}
// GetManageDNS - if manage DNS enabled or not
func GetManageDNS() bool {
return GetServerSettings().ManageDNS
}
// IsBasicAuthEnabled - checks if basic auth has been configured to be turned off
func IsBasicAuthEnabled() bool {
return GetServerSettings().BasicAuth
}
// IsEndpointDetectionEnabled - returns true if endpoint detection enabled
func IsEndpointDetectionEnabled() bool {
return GetServerSettings().EndpointDetection
}
// IsStunEnabled - returns true if STUN set to on
func IsStunEnabled() bool {
return GetServerSettings().Stun
}
func GetStunServers() string {
return GetServerSettings().StunServers
}
// GetAllowedEmailDomains - gets the allowed email domains for oauth signup
func GetAllowedEmailDomains() string {
return GetServerSettings().AllowedEmailDomains
}
func GetVerbosity() int32 {
return GetServerSettings().Verbosity
}
func Mask() string {
return ("..................")
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
"github.com/posthog/posthog-go" "github.com/posthog/posthog-go"
@@ -33,7 +34,7 @@ func SetFreeTierForTelemetry(freeTierFlag bool) {
// sendTelemetry - gathers telemetry data and sends to posthog // sendTelemetry - gathers telemetry data and sends to posthog
func sendTelemetry() error { func sendTelemetry() error {
if servercfg.Telemetry() == "off" { if Telemetry() == "off" {
return nil return nil
} }

View File

@@ -62,6 +62,7 @@ var CreateDefaultUserPolicies = func(netID models.NetworkID) {}
var GetUserGroupsInNetwork = func(netID models.NetworkID) (networkGrps map[models.UserGroupID]models.UserGroup) { return } var GetUserGroupsInNetwork = func(netID models.NetworkID) (networkGrps map[models.UserGroupID]models.UserGroup) { return }
var GetUserGroup = func(groupId models.UserGroupID) (userGrps models.UserGroup, err error) { return } var GetUserGroup = func(groupId models.UserGroupID) (userGrps models.UserGroup, err error) { return }
var AddGlobalNetRolesToAdmins = func(u *models.User) {} var AddGlobalNetRolesToAdmins = func(u *models.User) {}
var EmailInit = func() {}
// GetRole - fetches role template by id // GetRole - fetches role template by id
func GetRole(roleID models.UserRoleID) (models.UserRolePermissionTemplate, error) { func GetRole(roleID models.UserRoleID) (models.UserRolePermissionTemplate, error) {

View File

@@ -20,6 +20,7 @@ import (
// Run - runs all migrations // Run - runs all migrations
func Run() { func Run() {
settings()
updateEnrollmentKeys() updateEnrollmentKeys()
assignSuperAdmin() assignSuperAdmin()
createDefaultTagsAndPolicies() createDefaultTagsAndPolicies()
@@ -498,3 +499,10 @@ func migrateToGws() {
logic.DeleteTag(models.TagID(fmt.Sprintf("%s.%s", netI.NetID, models.OldRemoteAccessTagName)), true) logic.DeleteTag(models.TagID(fmt.Sprintf("%s.%s", netI.NetID, models.OldRemoteAccessTagName)), true)
} }
} }
func settings() {
_, err := database.FetchRecords(database.SERVER_SETTINGS)
if database.IsEmptyRecord(err) {
logic.UpsertServerSettings(logic.GetServerSettingsFromEnv())
}
}

40
models/settings.go Normal file
View File

@@ -0,0 +1,40 @@
package models
type Theme string
const (
Dark Theme = "dark"
Light Theme = "light"
System Theme = "system"
)
type ServerSettings struct {
NetclientAutoUpdate bool `json:"netclientautoupdate"`
Verbosity int32 `json:"verbosity"`
AuthProvider string `json:"authprovider"`
OIDCIssuer string `json:"oidcissuer"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
AzureTenant string `json:"azure_tenant"`
Telemetry string `json:"telemetry"`
BasicAuth bool `json:"basic_auth"`
JwtValidityDuration int `json:"jwt_validity_duration"`
RacAutoDisable bool `json:"rac_auto_disable"`
RacRestrictToSingleNetwork bool `json:"rac_restrict_to_single_network"`
EndpointDetection bool `json:"endpoint_detection"`
AllowedEmailDomains string `json:"allowed_email_domains"`
EmailSenderAddr string `json:"email_sender_addr"`
EmailSenderUser string `json:"email_sender_user"`
EmailSenderPassword string `json:"email_sender_password"`
SmtpHost string `json:"smtp_host"`
SmtpPort int `json:"smtp_port"`
MetricInterval string `json:"metric_interval"`
MetricsPort int `json:"metrics_port"`
ManageDNS bool `json:"manage_dns"`
DefaultDomain string `json:"default_domain"`
Stun bool `json:"stun"`
StunServers string `json:"stun_servers"`
Theme Theme `json:"theme"`
TextSize string `json:"text_size"`
ReducedMotion bool `json:"reduced_motion"`
}

View File

@@ -21,7 +21,7 @@ func PublishPeerUpdate(replacePeers bool) error {
return nil return nil
} }
if servercfg.GetManageDNS() { if logic.GetManageDNS() {
sendDNSSync() sendDNSSync()
} }

View File

@@ -47,7 +47,7 @@ var (
) )
func getCurrentAuthFunctions() map[string]interface{} { func getCurrentAuthFunctions() map[string]interface{} {
var authInfo = servercfg.GetAuthProviderInfo() var authInfo = logic.GetAuthProviderInfo(logic.GetServerSettings())
var authProvider = authInfo[0] var authProvider = authInfo[0]
switch authProvider { switch authProvider {
case google_provider_name: case google_provider_name:
@@ -74,7 +74,7 @@ func InitializeAuthProvider() string {
if err != nil { if err != nil {
logger.FatalLog("failed to set auth_secret", err.Error()) logger.FatalLog("failed to set auth_secret", err.Error())
} }
var authInfo = servercfg.GetAuthProviderInfo() var authInfo = logic.GetAuthProviderInfo(logic.GetServerSettings())
var serverConn = servercfg.GetAPIHost() var serverConn = servercfg.GetAPIHost()
if strings.Contains(serverConn, "localhost") || strings.Contains(serverConn, "127.0.0.1") { if strings.Contains(serverConn, "localhost") || strings.Contains(serverConn, "127.0.0.1") {
serverConn = "http://" + serverConn serverConn = "http://" + serverConn
@@ -275,7 +275,7 @@ func isStateCached(state string) bool {
// isEmailAllowed - checks if email is allowed to signup // isEmailAllowed - checks if email is allowed to signup
func isEmailAllowed(email string) bool { func isEmailAllowed(email string) bool {
allowedDomains := servercfg.GetAllowedEmailDomains() allowedDomains := logic.GetAllowedEmailDomains()
domains := strings.Split(allowedDomains, ",") domains := strings.Split(allowedDomains, ",")
if len(domains) == 1 && domains[0] == "*" { if len(domains) == 1 && domains[0] == "*" {
return true return true

View File

@@ -35,7 +35,7 @@ func initAzureAD(redirectURL string, clientID string, clientSecret string) {
ClientID: clientID, ClientID: clientID,
ClientSecret: clientSecret, ClientSecret: clientSecret,
Scopes: []string{"User.Read", "email", "profile", "openid"}, Scopes: []string{"User.Read", "email", "profile", "openid"},
Endpoint: microsoft.AzureADEndpoint(servercfg.GetAzureTenant()), Endpoint: microsoft.AzureADEndpoint(logic.GetAzureTenant()),
} }
} }

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"regexp" "regexp"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/logic"
) )
type EmailSenderType string type EmailSenderType string
@@ -16,14 +16,14 @@ const (
Resend EmailSenderType = "resend" Resend EmailSenderType = "resend"
) )
func init() { func Init() {
smtpSender := &SmtpSender{ smtpSender := &SmtpSender{
SmtpHost: servercfg.GetSmtpHost(), SmtpHost: logic.GetSmtpHost(),
SmtpPort: servercfg.GetSmtpPort(), SmtpPort: logic.GetSmtpPort(),
SenderEmail: servercfg.GetSenderEmail(), SenderEmail: logic.GetSenderEmail(),
SendUser: servercfg.GetSenderUser(), SendUser: logic.GetSenderUser(),
SenderPass: servercfg.GetEmaiSenderPassword(), SenderPass: logic.GetEmaiSenderPassword(),
} }
if smtpSender.SendUser == "" { if smtpSender.SendUser == "" {
smtpSender.SendUser = smtpSender.SenderEmail smtpSender.SendUser = smtpSender.SenderEmail

View File

@@ -13,6 +13,7 @@ import (
"github.com/gravitl/netmaker/mq" "github.com/gravitl/netmaker/mq"
"github.com/gravitl/netmaker/pro/auth" "github.com/gravitl/netmaker/pro/auth"
proControllers "github.com/gravitl/netmaker/pro/controllers" proControllers "github.com/gravitl/netmaker/pro/controllers"
"github.com/gravitl/netmaker/pro/email"
proLogic "github.com/gravitl/netmaker/pro/logic" proLogic "github.com/gravitl/netmaker/pro/logic"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
"golang.org/x/exp/slog" "golang.org/x/exp/slog"
@@ -79,7 +80,7 @@ func InitPro() {
addTrialLicenseHook() addTrialLicenseHook()
} }
if servercfg.GetServerConfig().RacAutoDisable { if logic.GetRacAutoDisable() {
AddRacHooks() AddRacHooks()
} }
@@ -91,6 +92,7 @@ func InitPro() {
} }
proLogic.LoadNodeMetricsToCache() proLogic.LoadNodeMetricsToCache()
proLogic.InitFailOverCache() proLogic.InitFailOverCache()
email.Init()
}) })
logic.ResetFailOver = proLogic.ResetFailOver logic.ResetFailOver = proLogic.ResetFailOver
logic.ResetFailedOverPeer = proLogic.ResetFailedOverPeer logic.ResetFailedOverPeer = proLogic.ResetFailedOverPeer
@@ -135,6 +137,8 @@ func InitPro() {
logic.GetUserGroupsInNetwork = proLogic.GetUserGroupsInNetwork logic.GetUserGroupsInNetwork = proLogic.GetUserGroupsInNetwork
logic.GetUserGroup = proLogic.GetUserGroup logic.GetUserGroup = proLogic.GetUserGroup
logic.GetNodeStatus = proLogic.GetNodeStatus logic.GetNodeStatus = proLogic.GetNodeStatus
logic.InitializeAuthProvider = auth.InitializeAuthProvider
logic.EmailInit = email.Init
} }
func retrieveProLogo() string { func retrieveProLogo() string {

View File

@@ -9,11 +9,12 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/gravitl/netmaker/utils"
"io" "io"
"net/http" "net/http"
"time" "time"
"github.com/gravitl/netmaker/utils"
"golang.org/x/crypto/nacl/box" "golang.org/x/crypto/nacl/box"
"golang.org/x/exp/slog" "golang.org/x/exp/slog"

View File

@@ -10,7 +10,6 @@ import (
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/mq" "github.com/gravitl/netmaker/mq"
"github.com/gravitl/netmaker/servercfg"
"golang.org/x/exp/slog" "golang.org/x/exp/slog"
) )
@@ -41,7 +40,7 @@ func racAutoDisableHook() error {
} }
currentTime := time.Now() currentTime := time.Now()
validityDuration := servercfg.GetJwtValidityDuration() validityDuration := logic.GetJwtValidityDuration()
for _, user := range users { for _, user := range users {
if user.PlatformRoleID == models.AdminRole || if user.PlatformRoleID == models.AdminRole ||
user.PlatformRoleID == models.SuperAdminRole { user.PlatformRoleID == models.SuperAdminRole {

View File

@@ -16,21 +16,16 @@ import (
// that it is easier to prevent a task from // that it is easier to prevent a task from
// being executed again. // being executed again.
type Job struct { type Job struct {
ID string `gorm:"id;primary_key"` ID string `gorm:"primaryKey"`
CreatedAt time.Time `gorm:"created_at"` CreatedAt time.Time
}
// TableName returns the name of the jobs table.
func (j *Job) TableName() string {
return "jobs"
} }
// Create creates a job record in the jobs table. // Create creates a job record in the jobs table.
func (j *Job) Create(ctx context.Context) error { func (j *Job) Create(ctx context.Context) error {
return db.FromContext(ctx).Table(j.TableName()).Create(j).Error return db.FromContext(ctx).Model(&Job{}).Create(j).Error
} }
// Get returns a job record with the given Job.ID. // Get returns a job record with the given Job.ID.
func (j *Job) Get(ctx context.Context) error { func (j *Job) Get(ctx context.Context) error {
return db.FromContext(ctx).Table(j.TableName()).Where("id = ?", j.ID).First(j).Error return db.FromContext(ctx).Model(&Job{}).Where("id = ?", j.ID).First(j).Error
} }

View File

@@ -2,6 +2,7 @@ package servercfg
import ( import (
"errors" "errors"
"fmt"
"io" "io"
"net/http" "net/http"
"os" "os"
@@ -11,11 +12,8 @@ import (
"time" "time"
"github.com/gravitl/netmaker/config" "github.com/gravitl/netmaker/config"
"github.com/gravitl/netmaker/models"
) )
var ServerInfo = GetServerInfo()
// EmqxBrokerType denotes the broker type for EMQX MQTT // EmqxBrokerType denotes the broker type for EMQX MQTT
const EmqxBrokerType = "emqx" const EmqxBrokerType = "emqx"
@@ -116,6 +114,18 @@ func GetJwtValidityDuration() time.Duration {
return defaultDuration return defaultDuration
} }
// GetJwtValidityDuration - returns the JWT validity duration in seconds
func GetJwtValidityDurationFromEnv() int {
var defaultDuration = 43200
if os.Getenv("JWT_VALIDITY_DURATION") != "" {
t, err := strconv.Atoi(os.Getenv("JWT_VALIDITY_DURATION"))
if err == nil {
return t
}
}
return defaultDuration
}
// GetRacAutoDisable - returns whether the feature to autodisable RAC is enabled // GetRacAutoDisable - returns whether the feature to autodisable RAC is enabled
func GetRacAutoDisable() bool { func GetRacAutoDisable() bool {
return os.Getenv("RAC_AUTO_DISABLE") == "true" return os.Getenv("RAC_AUTO_DISABLE") == "true"
@@ -126,39 +136,6 @@ func GetRacRestrictToSingleNetwork() bool {
return os.Getenv("RAC_RESTRICT_TO_SINGLE_NETWORK") == "true" return os.Getenv("RAC_RESTRICT_TO_SINGLE_NETWORK") == "true"
} }
// GetServerInfo - gets the server config into memory from file or env
func GetServerInfo() models.ServerConfig {
var cfg models.ServerConfig
cfg.Server = GetServer()
if GetBrokerType() == EmqxBrokerType {
cfg.MQUserName = "HOST_ID"
cfg.MQPassword = "HOST_PASS"
} else {
cfg.MQUserName = GetMqUserName()
cfg.MQPassword = GetMqPassword()
}
cfg.APIHost = GetAPIHost()
cfg.API = GetAPIConnString()
cfg.CoreDNSAddr = GetCoreDNSAddr()
cfg.APIPort = GetAPIPort()
cfg.DNSMode = "off"
cfg.Broker = GetPublicBrokerEndpoint()
cfg.BrokerType = GetBrokerType()
if IsDNSMode() {
cfg.DNSMode = "on"
}
cfg.Version = GetVersion()
cfg.IsPro = IsPro
cfg.MetricInterval = GetMetricInterval()
cfg.MetricsPort = GetMetricsPort()
cfg.ManageDNS = GetManageDNS()
cfg.Stun = IsStunEnabled()
cfg.StunServers = GetStunServers()
cfg.DefaultDomain = GetDefaultDomain()
cfg.EndpointDetection = IsEndpointDetectionEnabled()
return cfg
}
// GetFrontendURL - gets the frontend url // GetFrontendURL - gets the frontend url
func GetFrontendURL() string { func GetFrontendURL() string {
var frontend = "" var frontend = ""
@@ -167,6 +144,9 @@ func GetFrontendURL() string {
} else if config.Config.Server.FrontendURL != "" { } else if config.Config.Server.FrontendURL != "" {
frontend = config.Config.Server.FrontendURL frontend = config.Config.Server.FrontendURL
} }
if frontend == "" {
return fmt.Sprintf("https://dashboard.%s", GetNmBaseDomain())
}
return frontend return frontend
} }