| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377 | package controllerimport (	"bytes"	"encoding/base64"	"encoding/json"	"errors"	"fmt"	"github.com/pquerna/otp"	"image/png"	"net/http"	"reflect"	"time"	"github.com/google/uuid"	"github.com/gorilla/mux"	"github.com/gorilla/websocket"	"github.com/gravitl/netmaker/auth"	"github.com/gravitl/netmaker/logger"	"github.com/gravitl/netmaker/logic"	"github.com/gravitl/netmaker/models"	"github.com/gravitl/netmaker/mq"	"github.com/gravitl/netmaker/schema"	"github.com/gravitl/netmaker/servercfg"	"github.com/pquerna/otp/totp"	"golang.org/x/exp/slog")var (	upgrader = websocket.Upgrader{})var ListRoles = listRolesfunc userHandlers(r *mux.Router) {	r.HandleFunc("/api/users/adm/hassuperadmin", hasSuperAdmin).Methods(http.MethodGet)	r.HandleFunc("/api/users/adm/createsuperadmin", createSuperAdmin).Methods(http.MethodPost)	r.HandleFunc("/api/users/adm/transfersuperadmin/{username}", logic.SecurityCheck(true, http.HandlerFunc(transferSuperAdmin))).		Methods(http.MethodPost)	r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods(http.MethodPost)	r.HandleFunc("/api/users/{username}/auth/init-totp", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(initiateTOTPSetup)))).Methods(http.MethodPost)	r.HandleFunc("/api/users/{username}/auth/complete-totp", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(completeTOTPSetup)))).Methods(http.MethodPost)	r.HandleFunc("/api/users/{username}/auth/verify-totp", logic.PreAuthCheck(logic.ContinueIfUserMatch(http.HandlerFunc(verifyTOTP)))).Methods(http.MethodPost)	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUser))).Methods(http.MethodPut)	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).Methods(http.MethodPost)	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).Methods(http.MethodDelete)	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet)	r.HandleFunc("/api/users/{username}/enable", logic.SecurityCheck(true, http.HandlerFunc(enableUserAccount))).Methods(http.MethodPost)	r.HandleFunc("/api/users/{username}/disable", logic.SecurityCheck(true, http.HandlerFunc(disableUserAccount))).Methods(http.MethodPost)	r.HandleFunc("/api/v1/users", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserV1)))).Methods(http.MethodGet)	r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet)	r.HandleFunc("/api/v1/users/roles", logic.SecurityCheck(true, http.HandlerFunc(ListRoles))).Methods(http.MethodGet)	r.HandleFunc("/api/v1/users/access_token", logic.SecurityCheck(true, http.HandlerFunc(createUserAccessToken))).Methods(http.MethodPost)	r.HandleFunc("/api/v1/users/access_token", logic.SecurityCheck(true, http.HandlerFunc(getUserAccessTokens))).Methods(http.MethodGet)	r.HandleFunc("/api/v1/users/access_token", logic.SecurityCheck(true, http.HandlerFunc(deleteUserAccessTokens))).Methods(http.MethodDelete)	r.HandleFunc("/api/v1/users/logout", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(logout)))).Methods(http.MethodPost)}// @Summary     Authenticate a user to retrieve an authorization token// @Router      /api/v1/users/{username}/access_token [post]// @Tags        Auth// @Accept      json// @Param       body body models.UserAuthParams true "Authentication parameters"// @Success     200 {object} models.SuccessResponse// @Failure     400 {object} models.ErrorResponse// @Failure     401 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc createUserAccessToken(w http.ResponseWriter, r *http.Request) {	// Auth request consists of Mac Address and Password (from node that is authorizing	// in case of Master, auth is ignored and mac is set to "mastermac"	var req schema.UserAccessToken	err := json.NewDecoder(r.Body).Decode(&req)	if err != nil {		logger.Log(0, "error decoding request body: ",			err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))		return	}	if req.Name == "" {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("name is required"), logic.BadReq))		return	}	if req.UserName == "" {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), logic.BadReq))		return	}	caller, err := logic.GetUser(r.Header.Get("user"))	if err != nil {		logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.UnAuthorized))		return	}	user, err := logic.GetUser(req.UserName)	if err != nil {		logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.UnAuthorized))		return	}	if caller.UserName != user.UserName && caller.PlatformRoleID != models.SuperAdminRole {		if caller.PlatformRoleID == models.AdminRole {			if user.PlatformRoleID == models.SuperAdminRole || user.PlatformRoleID == models.AdminRole {				logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to create token for user "+user.UserName), logic.Forbidden_Msg))				return			}		} else {			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to create token for user "+user.UserName), logic.Forbidden_Msg))			return		}	}	req.ID = uuid.New().String()	req.CreatedBy = r.Header.Get("user")	req.CreatedAt = time.Now()	jwt, err := logic.CreateUserAccessJwtToken(user.UserName, user.PlatformRoleID, req.ExpiresAt, req.ID)	if jwt == "" {		// very unlikely that err is !nil and no jwt returned, but handle it anyways.		logic.ReturnErrorResponse(			w,			r,			logic.FormatError(errors.New("error creating access token "+err.Error()), logic.Internal),		)		return	}	err = req.Create(r.Context())	if err != nil {		logic.ReturnErrorResponse(			w,			r,			logic.FormatError(errors.New("error creating access token "+err.Error()), logic.Internal),		)		return	}	logic.LogEvent(&models.Event{		Action: models.Create,		Source: models.Subject{			ID:   caller.UserName,			Name: caller.UserName,			Type: models.UserSub,		},		TriggeredBy: caller.UserName,		Target: models.Subject{			ID:   req.ID,			Name: req.Name,			Type: models.UserAccessTokenSub,			Info: req,		},		Origin: models.Dashboard,	})	logic.ReturnSuccessResponseWithJson(w, r, models.SuccessfulUserLoginResponse{		AuthToken: jwt,		UserName:  req.UserName,	}, "api access token has generated for user "+req.UserName)}// @Summary     Authenticate a user to retrieve an authorization token// @Router      /api/v1/users/{username}/access_token [post]// @Tags        Auth// @Accept      json// @Param       body body models.UserAuthParams true "Authentication parameters"// @Success     200 {object} models.SuccessResponse// @Failure     400 {object} models.ErrorResponse// @Failure     401 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc getUserAccessTokens(w http.ResponseWriter, r *http.Request) {	username := r.URL.Query().Get("username")	if username == "" {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), "badrequest"))		return	}	logic.ReturnSuccessResponseWithJson(w, r, (&schema.UserAccessToken{UserName: username}).ListByUser(r.Context()), "fetched api access tokens for user "+username)}// @Summary     Authenticate a user to retrieve an authorization token// @Router      /api/v1/users/{username}/access_token [post]// @Tags        Auth// @Accept      json// @Param       body body models.UserAuthParams true "Authentication parameters"// @Success     200 {object} models.SuccessResponse// @Failure     400 {object} models.ErrorResponse// @Failure     401 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc deleteUserAccessTokens(w http.ResponseWriter, r *http.Request) {	id := r.URL.Query().Get("id")	if id == "" {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("id is required"), "badrequest"))		return	}	a := schema.UserAccessToken{		ID: id,	}	err := a.Get(r.Context())	if err != nil {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("token does not exist"), "badrequest"))		return	}	caller, err := logic.GetUser(r.Header.Get("user"))	if err != nil {		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized"))		return	}	user, err := logic.GetUser(a.UserName)	if err != nil {		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized"))		return	}	if caller.UserName != user.UserName && caller.PlatformRoleID != models.SuperAdminRole {		if caller.PlatformRoleID == models.AdminRole {			if user.PlatformRoleID == models.SuperAdminRole || user.PlatformRoleID == models.AdminRole {				logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to delete token of user "+user.UserName), logic.Forbidden_Msg))				return			}		} else {			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to delete token of user "+user.UserName), logic.Forbidden_Msg))			return		}	}	err = (&schema.UserAccessToken{ID: id}).Delete(r.Context())	if err != nil {		logic.ReturnErrorResponse(			w,			r,			logic.FormatError(errors.New("error deleting access token "+err.Error()), "internal"),		)		return	}	logic.LogEvent(&models.Event{		Action: models.Delete,		Source: models.Subject{			ID:   caller.UserName,			Name: caller.UserName,			Type: models.UserSub,		},		TriggeredBy: caller.UserName,		Target: models.Subject{			ID:   a.ID,			Name: a.Name,			Type: models.UserAccessTokenSub,			Info: a,		},		Origin: models.Dashboard,	})	logic.ReturnSuccessResponseWithJson(w, r, nil, "revoked access token")}// @Summary     Authenticate a user to retrieve an authorization token// @Router      /api/users/adm/authenticate [post]// @Tags        Auth// @Accept      json// @Param       body body models.UserAuthParams true "Authentication parameters"// @Success     200 {object} models.SuccessResponse// @Failure     400 {object} models.ErrorResponse// @Failure     401 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc authenticateUser(response http.ResponseWriter, request *http.Request) {	// Auth request consists of Mac Address and Password (from node that is authorizing	// in case of Master, auth is ignored and mac is set to "mastermac"	var authRequest models.UserAuthParams	var errorResponse = models.ErrorResponse{		Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",	}	decoder := json.NewDecoder(request.Body)	decoderErr := decoder.Decode(&authRequest)	defer request.Body.Close()	if decoderErr != nil {		logger.Log(0, "error decoding request body: ",			decoderErr.Error())		logic.ReturnErrorResponse(response, request, errorResponse)		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.AccountDisabled {		err = errors.New("user account disabled")		logic.ReturnErrorResponse(response, request, logic.FormatError(err, "unauthorized"))		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" {		// request came from UI, if normal user block Login		role, err := logic.GetRole(user.PlatformRoleID)		if err != nil {			logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("access denied to dashboard"), "unauthorized"))			return		}		if role.DenyDashboardAccess {			logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("access denied to dashboard"), "unauthorized"))			return		}		// log user activity		logic.LogEvent(&models.Event{			Action: models.Login,			Source: models.Subject{				ID:   user.UserName,				Name: user.UserName,				Type: models.UserSub,			},			TriggeredBy: user.UserName,			Target: models.Subject{				ID:   models.DashboardSub.String(),				Name: models.DashboardSub.String(),				Type: models.DashboardSub,			},			Origin: models.Dashboard,		})	} else {		logic.LogEvent(&models.Event{			Action: models.Login,			Source: models.Subject{				ID:   user.UserName,				Name: user.UserName,				Type: models.UserSub,			},			TriggeredBy: user.UserName,			Target: models.Subject{				ID:   models.ClientAppSub.String(),				Name: models.ClientAppSub.String(),				Type: models.ClientAppSub,			},			Origin: models.ClientApp,		})	}	username := authRequest.UserName	jwt, err := logic.VerifyAuthRequest(authRequest)	if err != nil {		logger.Log(0, username, "user validation failed: ",			err.Error())		logic.ReturnErrorResponse(response, request, logic.FormatError(err, "badrequest"))		return	}	if jwt == "" {		// very unlikely that err is !nil and no jwt returned, but handle it anyways.		logger.Log(0, username, "jwt token is empty")		logic.ReturnErrorResponse(			response,			request,			logic.FormatError(errors.New("no token returned"), "internal"),		)		return	}	var successResponse models.SuccessResponse	if user.IsMFAEnabled {		successResponse = models.SuccessResponse{			Code:    http.StatusOK,			Message: "W1R3: TOTP required",			Response: models.PartialUserLoginResponse{				UserName:     username,				PreAuthToken: jwt,			},		}	} else {		successResponse = models.SuccessResponse{			Code:    http.StatusOK,			Message: "W1R3: Device " + username + " Authorized",			Response: models.SuccessfulUserLoginResponse{				UserName:  username,				AuthToken: jwt,			},		}	}	// Send back the JWT	successJSONResponse, jsonError := json.Marshal(successResponse)	if jsonError != nil {		logger.Log(0, username,			"error marshalling resp: ", jsonError.Error())		logic.ReturnErrorResponse(response, request, errorResponse)		return	}	logger.Log(2, username, "was authenticated")	response.Header().Set("Content-Type", "application/json")	response.Write(successJSONResponse)	go func() {		if servercfg.IsPro {			// enable all associeated clients for the user			clients, err := logic.GetAllExtClients()			if err != nil {				slog.Error("error getting clients: ", "error", err)				return			}			for _, client := range clients {				if client.OwnerID == username && !client.Enabled {					slog.Info(						fmt.Sprintf(							"enabling ext client %s for user %s due to RAC autodisabling feature",							client.ClientID,							client.OwnerID,						),					)					if newClient, err := logic.ToggleExtClientConnectivity(&client, true); err != nil {						slog.Error(							"error enabling ext client in RAC autodisable hook",							"error",							err,						)						continue // dont return but try for other clients					} else {						// publish peer update to ingress gateway						if ingressNode, err := logic.GetNodeByID(newClient.IngressGatewayID); err == nil {							if err = mq.PublishPeerUpdate(false); err != nil {								slog.Error("error updating ext clients on", "ingress", ingressNode.ID.String(), "err", err.Error())							}						}					}				}			}		}	}()}// @Summary     Initiate setting up TOTP 2FA for a user.// @Router      /api/users/auth/init-totp [post]// @Tags        Auth// @Success     200 {object} models.SuccessResponse// @Failure     400 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc initiateTOTPSetup(w http.ResponseWriter, r *http.Request) {	username := r.Header.Get("user")	user, err := logic.GetUser(username)	if err != nil {		logger.Log(0, "failed to get user: ", err.Error())		err = fmt.Errorf("user not found: %v", err)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	if user.AuthType == models.OAuth {		err = fmt.Errorf("auth type is %s, cannot process totp setup", user.AuthType)		logger.Log(0, err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	key, err := totp.Generate(totp.GenerateOpts{		Issuer:      "Netmaker",		AccountName: username,	})	if err != nil {		err = fmt.Errorf("failed to generate totp key: %v", err)		logger.Log(0, err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	qrCodeImg, err := key.Image(200, 200)	if err != nil {		err = fmt.Errorf("failed to generate totp key: %v", err)		logger.Log(0, err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	var qrCodePng bytes.Buffer	err = png.Encode(&qrCodePng, qrCodeImg)	if err != nil {		err = fmt.Errorf("failed to generate totp key: %v", err)		logger.Log(0, err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	qrCode := "data:image/png;base64," + base64.StdEncoding.EncodeToString(qrCodePng.Bytes())	logic.ReturnSuccessResponseWithJson(w, r, models.TOTPInitiateResponse{		OTPAuthURL:          key.URL(),		OTPAuthURLSignature: logic.GenerateOTPAuthURLSignature(key.URL()),		QRCode:              qrCode,	}, "totp setup initiated")}// @Summary     Verify and complete setting up TOTP 2FA for a user.// @Router      /api/users/auth/complete-totp [post]// @Tags        Auth// @Param       body body models.UserTOTPVerificationParams true "TOTP verification parameters"// @Success     200 {object} models.SuccessResponse// @Failure     400 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc completeTOTPSetup(w http.ResponseWriter, r *http.Request) {	username := r.Header.Get("user")	var req models.UserTOTPVerificationParams	err := json.NewDecoder(r.Body).Decode(&req)	if err != nil {		logger.Log(0, "failed to decode request body: ", err.Error())		err = fmt.Errorf("invalid request body: %v", err)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	if !logic.VerifyOTPAuthURL(req.OTPAuthURL, req.OTPAuthURLSignature) {		err = fmt.Errorf("otp auth url signature mismatch")		logger.Log(0, err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	user, err := logic.GetUser(username)	if err != nil {		logger.Log(0, "failed to get user: ", err.Error())		err = fmt.Errorf("user not found: %v", err)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	if user.AuthType == models.OAuth {		err = fmt.Errorf("auth type is %s, cannot process totp setup", user.AuthType)		logger.Log(0, err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	otpAuthURL, err := otp.NewKeyFromURL(req.OTPAuthURL)	if err != nil {		err = fmt.Errorf("error parsing otp auth url: %v", err)		logger.Log(0, err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	totpSecret := otpAuthURL.Secret()	if totp.Validate(req.TOTP, totpSecret) {		user.IsMFAEnabled = true		user.TOTPSecret = totpSecret		err = logic.UpsertUser(*user)		if err != nil {			err = fmt.Errorf("error upserting user: %v", err)			logger.Log(0, err.Error())			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))			return		}		logic.ReturnSuccessResponse(w, r, fmt.Sprintf("totp setup complete for user %s", username))	} else {		err = fmt.Errorf("cannot setup totp for user %s: invalid otp", username)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))	}}// @Summary     Verify a user's TOTP token.// @Router      /api/users/auth/verify-totp [post]// @Tags        Auth// @Accept      json// @Param       body body models.UserTOTPVerificationParams true "TOTP verification parameters"// @Success     200 {object} models.SuccessResponse// @Failure     400 {object} models.ErrorResponse// @Failure     401 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc verifyTOTP(w http.ResponseWriter, r *http.Request) {	username := r.Header.Get("user")	var req models.UserTOTPVerificationParams	err := json.NewDecoder(r.Body).Decode(&req)	if err != nil {		logger.Log(0, "failed to decode request body: ", err.Error())		err = fmt.Errorf("invalid request body: %v", err)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	user, err := logic.GetUser(username)	if err != nil {		logger.Log(0, "failed to get user: ", err.Error())		err = fmt.Errorf("user not found: %v", err)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	if !user.IsMFAEnabled {		err = fmt.Errorf("mfa is disabled for user(%s), cannot process totp verification", username)		logger.Log(0, err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	if totp.Validate(req.TOTP, user.TOTPSecret) {		jwt, err := logic.CreateUserJWT(user.UserName, user.PlatformRoleID)		if err != nil {			err = fmt.Errorf("error creating token: %v", err)			logger.Log(0, err.Error())			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))			return		}		// update last login time		user.LastLoginTime = time.Now().UTC()		err = logic.UpsertUser(*user)		if err != nil {			err = fmt.Errorf("error upserting user: %v", err)			logger.Log(0, err.Error())			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))			return		}		logic.ReturnSuccessResponseWithJson(w, r, models.SuccessfulUserLoginResponse{			UserName:  username,			AuthToken: jwt,		}, "W1R3: User "+username+" Authorized")	} else {		err = fmt.Errorf("invalid otp")		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized"))	}}// @Summary     Check if the server has a super admin// @Router      /api/users/adm/hassuperadmin [get]// @Tags        Users// @Success     200 {object} bool// @Failure     500 {object} models.ErrorResponsefunc hasSuperAdmin(w http.ResponseWriter, r *http.Request) {	w.Header().Set("Content-Type", "application/json")	hasSuperAdmin, err := logic.HasSuperAdmin()	if err != nil {		logger.Log(0, "failed to check for admin: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	json.NewEncoder(w).Encode(hasSuperAdmin)}// @Summary     Get an individual user// @Router      /api/users/{username} [get]// @Tags        Users// @Param       username path string true "Username of the user to fetch"// @Success     200 {object} models.User// @Failure     500 {object} models.ErrorResponsefunc getUser(w http.ResponseWriter, r *http.Request) {	// set header.	w.Header().Set("Content-Type", "application/json")	var params = mux.Vars(r)	usernameFetched := params["username"]	user, err := logic.GetReturnUser(usernameFetched)	if err != nil {		logger.Log(0, usernameFetched, "failed to fetch user: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	logger.Log(2, r.Header.Get("user"), "fetched user", usernameFetched)	json.NewEncoder(w).Encode(user)}// @Summary     Enable a user's account// @Router      /api/users/{username}/enable [post]// @Tags        Users// @Param       username path string true "Username of the user to enable"// @Success     200 {object} models.SuccessResponse// @Failure     400 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc enableUserAccount(w http.ResponseWriter, r *http.Request) {	username := mux.Vars(r)["username"]	user, err := logic.GetUser(username)	if err != nil {		logger.Log(0, "failed to fetch user: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	user.AccountDisabled = false	err = logic.UpsertUser(*user)	if err != nil {		logger.Log(0, "failed to enable user account: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))	}	logic.ReturnSuccessResponse(w, r, "user account enabled")}// @Summary     Disable a user's account// @Router      /api/users/{username}/disable [post]// @Tags        Users// @Param       username path string true "Username of the user to disable"// @Success     200 {object} models.SuccessResponse// @Failure     400 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc disableUserAccount(w http.ResponseWriter, r *http.Request) {	username := mux.Vars(r)["username"]	user, err := logic.GetUser(username)	if err != nil {		logger.Log(0, "failed to fetch user: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	if user.PlatformRoleID == models.SuperAdminRole {		err = errors.New("cannot disable super-admin user account")		logger.Log(0, err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	user.AccountDisabled = true	err = logic.UpsertUser(*user)	if err != nil {		logger.Log(0, "failed to disable user account: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))	}	logic.ReturnSuccessResponse(w, r, "user account disabled")}// swagger:route GET /api/v1/users user getUserV1//// Get an individual user with role info.////			Schemes: https////			Security://	  		oauth////			Responses://				200: ReturnUserWithRolesAndGroupsfunc getUserV1(w http.ResponseWriter, r *http.Request) {	// set header.	w.Header().Set("Content-Type", "application/json")	usernameFetched := r.URL.Query().Get("username")	if usernameFetched == "" {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), "badrequest"))		return	}	user, err := logic.GetReturnUser(usernameFetched)	if err != nil {		logger.Log(0, usernameFetched, "failed to fetch user: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	userRoleTemplate, err := logic.GetRole(user.PlatformRoleID)	if err != nil {		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	resp := models.ReturnUserWithRolesAndGroups{		ReturnUser:   user,		PlatformRole: userRoleTemplate,		UserGroups:   map[models.UserGroupID]models.UserGroup{},	}	for gId := range user.UserGroups {		grp, err := logic.GetUserGroup(gId)		if err != nil {			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))			return		}		resp.UserGroups[gId] = grp	}	logger.Log(2, r.Header.Get("user"), "fetched user", usernameFetched)	logic.ReturnSuccessResponseWithJson(w, r, resp, "fetched user with role info")}// swagger:route GET /api/users user getUsers//// Get all users.////			Schemes: https////			Security://	  		oauth////			Responses://				200: userBodyResponsefunc getUsers(w http.ResponseWriter, r *http.Request) {	// set header.	w.Header().Set("Content-Type", "application/json")	users, err := logic.GetUsers()	if err != nil {		logger.Log(0, "failed to fetch users: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	logic.SortUsers(users[:])	logger.Log(2, r.Header.Get("user"), "fetched users")	json.NewEncoder(w).Encode(users)}// @Summary     Create a super admin// @Router      /api/users/adm/createsuperadmin [post]// @Tags        Users// @Param       body body models.User true "User details"// @Success     200 {object} models.User// @Failure     400 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc createSuperAdmin(w http.ResponseWriter, r *http.Request) {	w.Header().Set("Content-Type", "application/json")	var u models.User	err := json.NewDecoder(r.Body).Decode(&u)	if err != nil {		slog.Error("error decoding request body", "error", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	if !logic.IsBasicAuthEnabled() {		logic.ReturnErrorResponse(			w,			r,			logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),		)		return	}	err = logic.CreateSuperAdmin(&u)	if err != nil {		slog.Error("failed to create admin", "error", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	logger.Log(1, u.UserName, "was made a super admin")	json.NewEncoder(w).Encode(logic.ToReturnUser(u))}// @Summary     Transfer super admin role to another admin user// @Router      /api/users/adm/transfersuperadmin/{username} [post]// @Tags        Users// @Param       username path string true "Username of the user to transfer super admin role"// @Success     200 {object} models.User// @Failure     403 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc transferSuperAdmin(w http.ResponseWriter, r *http.Request) {	w.Header().Set("Content-Type", "application/json")	caller, err := logic.GetUser(r.Header.Get("user"))	if err != nil {		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))	}	if caller.PlatformRoleID != models.SuperAdminRole {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only superadmin can assign the superadmin role to another user"), "forbidden"))		return	}	var params = mux.Vars(r)	username := params["username"]	u, err := logic.GetUser(username)	if err != nil {		slog.Error("error getting user", "user", u.UserName, "error", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	if u.PlatformRoleID != models.AdminRole {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only admins can be promoted to superadmin role"), "forbidden"))		return	}	if !logic.IsBasicAuthEnabled() {		logic.ReturnErrorResponse(			w,			r,			logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),		)		return	}	u.PlatformRoleID = models.SuperAdminRole	err = logic.UpsertUser(*u)	if err != nil {		slog.Error("error updating user to superadmin: ", "user", u.UserName, "error", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	caller.PlatformRoleID = models.AdminRole	err = logic.UpsertUser(*caller)	if err != nil {		slog.Error("error demoting user to admin: ", "user", caller.UserName, "error", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	slog.Info("user was made a super admin", "user", u.UserName)	json.NewEncoder(w).Encode(logic.ToReturnUser(*u))}// @Summary     Create a user// @Router      /api/users/{username} [post]// @Tags        Users// @Param       username path string true "Username of the user to create"// @Param       body body models.User true "User details"// @Success     200 {object} models.User// @Failure     400 {object} models.ErrorResponse// @Failure     403 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc createUser(w http.ResponseWriter, r *http.Request) {	w.Header().Set("Content-Type", "application/json")	caller, err := logic.GetUser(r.Header.Get("user"))	if err != nil {		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	var user models.User	err = json.NewDecoder(r.Body).Decode(&user)	if err != nil {		logger.Log(0, user.UserName, "error decoding request body: ",			err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	if !servercfg.IsPro {		user.PlatformRoleID = models.AdminRole	}	if user.UserName == logic.MasterUser {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username not allowed"), "badrequest"))		return	}	if user.PlatformRoleID == "" {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("platform role is missing"), "badrequest"))		return	}	userRole, err := logic.GetRole(user.PlatformRoleID)	if err != nil {		err = errors.New("error fetching role " + user.PlatformRoleID.String() + " " + err.Error())		slog.Error("error creating new user: ", "user", user.UserName, "error", err)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	if userRole.ID == models.SuperAdminRole {		err = errors.New("additional superadmins cannot be created")		slog.Error("error creating new user: ", "user", user.UserName, "error", err)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))		return	}	if caller.PlatformRoleID != models.SuperAdminRole && user.PlatformRoleID == models.AdminRole {		err = errors.New("only superadmin can create admin users")		slog.Error("error creating new user: ", "user", user.UserName, "error", err)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))		return	}	if !servercfg.IsPro && user.PlatformRoleID != models.AdminRole {		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("non-admins users can only be created on Pro version"), "forbidden"))		return	}	err = logic.CreateUser(&user)	if err != nil {		slog.Error("error creating new user: ", "user", user.UserName, "error", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	logic.LogEvent(&models.Event{		Action: models.Create,		Source: models.Subject{			ID:   caller.UserName,			Name: caller.UserName,			Type: models.UserSub,		},		TriggeredBy: caller.UserName,		Target: models.Subject{			ID:   user.UserName,			Name: user.UserName,			Type: models.UserSub,			Info: user,		},		Origin: models.Dashboard,	})	logic.DeleteUserInvite(user.UserName)	logic.DeletePendingUser(user.UserName)	go mq.PublishPeerUpdate(false)	slog.Info("user was created", "username", user.UserName)	json.NewEncoder(w).Encode(logic.ToReturnUser(user))}// @Summary     Update a user// @Router      /api/users/{username} [put]// @Tags        Users// @Param       username path string true "Username of the user to update"// @Param       body body models.User true "User details"// @Success     200 {object} models.User// @Failure     400 {object} models.ErrorResponse// @Failure     403 {object} models.ErrorResponse// @Failure     500 {object} models.ErrorResponsefunc updateUser(w http.ResponseWriter, r *http.Request) {	w.Header().Set("Content-Type", "application/json")	var params = mux.Vars(r)	// start here	var caller *models.User	var err error	var ismaster bool	if r.Header.Get("user") == logic.MasterUser {		ismaster = true	} else {		caller, err = logic.GetUser(r.Header.Get("user"))		if err != nil {			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		}	}	username := params["username"]	user, err := logic.GetUser(username)	if err != nil {		logger.Log(0, username,			"failed to update user info: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	var userchange models.User	// we decode our body request params	err = json.NewDecoder(r.Body).Decode(&userchange)	if err != nil {		slog.Error("failed to decode body", "error ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	if user.UserName != userchange.UserName {		logic.ReturnErrorResponse(			w,			r,			logic.FormatError(				errors.New("user in param and request body not matching"),				"badrequest",			),		)		return	}	selfUpdate := false	if !ismaster && caller.UserName == user.UserName {		selfUpdate = true	}	if !ismaster && !selfUpdate {		if caller.PlatformRoleID == models.AdminRole && user.PlatformRoleID == models.SuperAdminRole {			slog.Error("non-superadmin user", "caller", caller.UserName, "attempted to update superadmin user", username)			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))			return		}		if caller.PlatformRoleID != models.AdminRole && caller.PlatformRoleID != models.SuperAdminRole {			slog.Error("operation not allowed", "caller", caller.UserName, "attempted to update user", username)			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))			return		}		if caller.PlatformRoleID == models.AdminRole && user.PlatformRoleID == models.AdminRole {			slog.Error("an admin user does not have permissions to update another admin user", "caller", caller.UserName, "attempted to update admin user", username)			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("an admin user does not have permissions to update another admin user"), "forbidden"))			return		}		if caller.PlatformRoleID == models.AdminRole && userchange.PlatformRoleID == models.AdminRole {			err = errors.New("an admin user does not have permissions to assign the admin role to another user")			slog.Error(				"failed to update user",				"caller",				caller.UserName,				"attempted to update user",				username,				"error",				err,			)			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))			return		}	}	if !ismaster && selfUpdate {		if user.PlatformRoleID != userchange.PlatformRoleID {			slog.Error("user cannot change his own role", "caller", caller.UserName, "attempted to update user role", username)			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden"))			return		}		if logic.IsMFAEnforced() && user.IsMFAEnabled && !userchange.IsMFAEnabled {			err = errors.New("mfa is enforced, user cannot unset their own mfa")			slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))			return		}		if servercfg.IsPro {			// user cannot update his own roles and groups			if len(user.NetworkRoles) != len(userchange.NetworkRoles) || !reflect.DeepEqual(user.NetworkRoles, userchange.NetworkRoles) {				err = errors.New("user cannot update self update their network roles")				slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))				return			}			// user cannot update his own roles and groups			if len(user.UserGroups) != len(userchange.UserGroups) || !reflect.DeepEqual(user.UserGroups, userchange.UserGroups) {				err = errors.New("user cannot update self update their groups")				slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))				return			}		}	}	if ismaster {		if user.PlatformRoleID != models.SuperAdminRole && userchange.PlatformRoleID == models.SuperAdminRole {			slog.Error("operation not allowed", "caller", logic.MasterUser, "attempted to update user role to superadmin", username)			logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("attempted to update user role to superadmin"), "forbidden"))			return		}	}	if logic.IsOauthUser(user) == nil && userchange.Password != "" {		err := fmt.Errorf("cannot update user's password for an oauth user %s", username)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))		return	}	logic.AddGlobalNetRolesToAdmins(&userchange)	if userchange.PlatformRoleID != user.PlatformRoleID || !logic.CompareMaps(user.UserGroups, userchange.UserGroups) {		(&schema.UserAccessToken{UserName: user.UserName}).DeleteAllUserTokens(r.Context())	}	oldUser := *user	if ismaster {		caller = &models.User{			UserName: logic.MasterUser,		}	}	e := models.Event{		Action: models.Update,		Source: models.Subject{			ID:   caller.UserName,			Name: caller.UserName,			Type: models.UserSub,		},		TriggeredBy: caller.UserName,		Target: models.Subject{			ID:   user.UserName,			Name: user.UserName,			Type: models.UserSub,		},		Diff: models.Diff{			Old: oldUser,			New: userchange,		},		Origin: models.Dashboard,	}	user, err = logic.UpdateUser(&userchange, user)	if err != nil {		logger.Log(0, username,			"failed to update user info: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	logic.LogEvent(&e)	go mq.PublishPeerUpdate(false)	logger.Log(1, username, "was updated")	json.NewEncoder(w).Encode(logic.ToReturnUser(*user))}// @Summary     Delete a user// @Router      /api/users/{username} [delete]// @Tags        Users// @Param       username path string true "Username of the user to delete"// @Success     200 {string} string// @Failure     500 {object} models.ErrorResponsefunc deleteUser(w http.ResponseWriter, r *http.Request) {	// Set header	w.Header().Set("Content-Type", "application/json")	// get params	var params = mux.Vars(r)	caller, err := logic.GetUser(r.Header.Get("user"))	if err != nil {		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))	}	callerUserRole, err := logic.GetRole(caller.PlatformRoleID)	if err != nil {		slog.Error("failed to get role ", "role", callerUserRole.ID, "error", err)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	username := params["username"]	user, err := logic.GetUser(username)	if err != nil {		logger.Log(0, username,			"failed to update user info: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	userRole, err := logic.GetRole(user.PlatformRoleID)	if err != nil {		slog.Error("failed to get role ", "role", userRole.ID, "error", err)		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	if userRole.ID == models.SuperAdminRole {		slog.Error(			"failed to delete user: ", "user", username, "error", "superadmin cannot be deleted")		logic.ReturnErrorResponse(			w,			r,			logic.FormatError(fmt.Errorf("superadmin cannot be deleted"), "internal"),		)		return	}	if callerUserRole.ID != models.SuperAdminRole {		if callerUserRole.ID == models.AdminRole && userRole.ID == models.AdminRole {			slog.Error(				"failed to delete user: ",				"user",				username,				"error",				"admin cannot delete another admin user, including oneself",			)			logic.ReturnErrorResponse(				w,				r,				logic.FormatError(					fmt.Errorf("admin cannot delete another admin user, including oneself"),					"internal",				),			)			return		}	}	if user.AuthType == models.OAuth || user.ExternalIdentityProviderID != "" {		err = fmt.Errorf("cannot delete idp user %s", username)		logger.Log(0, username, "failed to delete user: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	err = logic.DeleteUser(username)	if err != nil {		logger.Log(0, username,			"failed to delete user: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	logic.LogEvent(&models.Event{		Action: models.Delete,		Source: models.Subject{			ID:   caller.UserName,			Name: caller.UserName,			Type: models.UserSub,		},		TriggeredBy: caller.UserName,		Target: models.Subject{			ID:   user.UserName,			Name: user.UserName,			Type: models.UserSub,		},		Origin: models.Dashboard,	})	// check and delete extclient with this ownerID	go func() {		extclients, err := logic.GetAllExtClients()		if err != nil {			slog.Error("failed to get extclients", "error", err)			return		}		for _, extclient := range extclients {			if extclient.OwnerID == user.UserName {				err = logic.DeleteExtClientAndCleanup(extclient)				if err != nil {					slog.Error("failed to delete extclient",						"id", extclient.ClientID, "owner", username, "error", err)				} else {					if err := mq.PublishDeletedClientPeerUpdate(&extclient); err != nil {						slog.Error("error setting ext peers: " + err.Error())					}				}			}		}		mq.PublishPeerUpdate(false)		if servercfg.IsDNSMode() {			logic.SetDNS()		}	}()	logger.Log(1, username, "was deleted")	json.NewEncoder(w).Encode(params["username"] + " deleted.")}// Called when vpn client dials in to start the auth flow and first stage is to get register URL itselffunc socketHandler(w http.ResponseWriter, r *http.Request) {	// Upgrade our raw HTTP connection to a websocket based one	conn, err := upgrader.Upgrade(w, r, nil)	if err != nil {		logger.Log(0, "error during connection upgrade for node sign-in:", err.Error())		return	}	if conn == nil {		logger.Log(0, "failed to establish web-socket connection during node sign-in")		return	}	// Start handling the session	go auth.SessionHandler(conn)}// @Summary     lists all user roles.// @Router      /api/v1/user/roles [get]// @Tags        Users// @Param       role_id query string true "roleid required to get the role details"// @Success     200 {object}  []models.UserRolePermissionTemplate// @Failure     500 {object} models.ErrorResponsefunc listRoles(w http.ResponseWriter, r *http.Request) {	var roles []models.UserRolePermissionTemplate	var err error	roles, err = logic.ListPlatformRoles()	if err != nil {		logic.ReturnErrorResponse(w, r, models.ErrorResponse{			Code:    http.StatusInternalServerError,			Message: err.Error(),		})		return	}	logic.ReturnSuccessResponseWithJson(w, r, roles, "successfully fetched user roles permission templates")}// swagger:route POST /api/v1/user/logout user logout//// LogOut user.////			Schemes: https////			Security://	  		oauth////			Responses://				200: userBodyResponsefunc logout(w http.ResponseWriter, r *http.Request) {	// set header.	w.Header().Set("Content-Type", "application/json")	userName := r.URL.Query().Get("username")	user, err := logic.GetUser(userName)	if err != nil {		logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))		return	}	var target models.SubjectType	if val := r.Header.Get("From-Ui"); val == "true" {		target = models.DashboardSub	} else {		target = models.ClientAppSub	}	if target != "" {		logic.LogEvent(&models.Event{			Action: models.LogOut,			Source: models.Subject{				ID:   user.UserName,				Name: user.UserName,				Type: models.UserSub,			},			TriggeredBy: user.UserName,			Target: models.Subject{				ID:   target.String(),				Name: target.String(),				Type: target,			},			Origin: models.Origin(target),		})	}	logic.ReturnSuccessResponse(w, r, "user logged out")}
 |