| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 | package controllerimport (	"encoding/json"	"fmt"	"net/http"	"time"	"github.com/gorilla/mux"	"github.com/gravitl/netmaker/logger"	"github.com/gravitl/netmaker/logic"	"github.com/gravitl/netmaker/logic/hostactions"	"github.com/gravitl/netmaker/models"	"github.com/gravitl/netmaker/mq"	"github.com/gravitl/netmaker/servercfg")func enrollmentKeyHandlers(r *mux.Router) {	r.HandleFunc("/api/v1/enrollment-keys", logic.SecurityCheck(true, http.HandlerFunc(createEnrollmentKey))).Methods(http.MethodPost)	r.HandleFunc("/api/v1/enrollment-keys", logic.SecurityCheck(true, http.HandlerFunc(getEnrollmentKeys))).Methods(http.MethodGet)	r.HandleFunc("/api/v1/enrollment-keys/{keyID}", logic.SecurityCheck(true, http.HandlerFunc(deleteEnrollmentKey))).Methods(http.MethodDelete)	r.HandleFunc("/api/v1/host/register/{token}", http.HandlerFunc(handleHostRegister)).Methods(http.MethodPost)}// swagger:route GET /api/v1/enrollment-keys enrollmentKeys getEnrollmentKeys//// Lists all EnrollmentKeys for admins.////			Schemes: https////			Security://	  		oauth////			Responses://				200: getEnrollmentKeysSlicefunc getEnrollmentKeys(w http.ResponseWriter, r *http.Request) {	currentKeys, err := logic.GetAllEnrollmentKeys()	if err != nil {		logger.Log(0, r.Header.Get("user"), "failed to fetch enrollment keys: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	for i := range currentKeys {		currentKey := currentKeys[i]		if err = logic.Tokenize(currentKey, servercfg.GetAPIHost()); err != nil {			logger.Log(0, r.Header.Get("user"), "failed to get token values for keys:", err.Error())			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))			return		}	}	// return JSON/API formatted keys	logger.Log(2, r.Header.Get("user"), "fetched enrollment keys")	w.WriteHeader(http.StatusOK)	json.NewEncoder(w).Encode(currentKeys)}// swagger:route DELETE /api/v1/enrollment-keys/{keyID} enrollmentKeys deleteEnrollmentKey//// Deletes an EnrollmentKey from Netmaker server.////			Schemes: https////			Security://	  		oauth////			Responses://				200: deleteEnrollmentKeyResponsefunc deleteEnrollmentKey(w http.ResponseWriter, r *http.Request) {	var params = mux.Vars(r)	keyID := params["keyID"]	err := logic.DeleteEnrollmentKey(keyID)	if err != nil {		logger.Log(0, r.Header.Get("user"), "failed to remove enrollment key: ", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	logger.Log(2, r.Header.Get("user"), "deleted enrollment key", keyID)	w.WriteHeader(http.StatusOK)}// swagger:route POST /api/v1/enrollment-keys enrollmentKeys createEnrollmentKey//// Creates an EnrollmentKey for hosts to use on Netmaker server.////			Schemes: https////			Security://	  		oauth////			Responses://				200: createEnrollmentKeyResponsefunc createEnrollmentKey(w http.ResponseWriter, r *http.Request) {	var enrollmentKeyBody models.APIEnrollmentKey	err := json.NewDecoder(r.Body).Decode(&enrollmentKeyBody)	if err != nil {		logger.Log(0, r.Header.Get("user"), "error decoding request body: ",			err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	var newTime time.Time	if enrollmentKeyBody.Expiration > 0 {		newTime = time.Unix(enrollmentKeyBody.Expiration, 0)	}	newEnrollmentKey, err := logic.CreateEnrollmentKey(enrollmentKeyBody.UsesRemaining, newTime, enrollmentKeyBody.Networks, enrollmentKeyBody.Tags, enrollmentKeyBody.Unlimited)	if err != nil {		logger.Log(0, r.Header.Get("user"), "failed to create enrollment key:", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	if err = logic.Tokenize(newEnrollmentKey, servercfg.GetAPIHost()); err != nil {		logger.Log(0, r.Header.Get("user"), "failed to create enrollment key:", err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	logger.Log(2, r.Header.Get("user"), "created enrollment key")	w.WriteHeader(http.StatusOK)	json.NewEncoder(w).Encode(newEnrollmentKey)}// swagger:route POST /api/v1/enrollment-keys/{token} enrollmentKeys handleHostRegister//// Handles a Netclient registration with server and add nodes accordingly.////			Schemes: https////			Security://	  		oauth////			Responses://				200: handleHostRegisterResponsefunc handleHostRegister(w http.ResponseWriter, r *http.Request) {	var params = mux.Vars(r)	token := params["token"]	logger.Log(0, "received registration attempt with token", token)	// check if token exists	enrollmentKey, err := logic.DeTokenize(token)	if err != nil {		logger.Log(0, "invalid enrollment key used", token, err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	// get the host	var newHost models.Host	if err = json.NewDecoder(r.Body).Decode(&newHost); err != nil {		logger.Log(0, r.Header.Get("user"), "error decoding request body: ",			err.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	hostExists := false	// check if host already exists	if hostExists = logic.HostExists(&newHost); hostExists && len(enrollmentKey.Networks) == 0 {		logger.Log(0, "host", newHost.ID.String(), newHost.Name, "attempted to re-register with no networks")		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("host already exists"), "badrequest"))		return	}	// version check	if !logic.IsVersionComptatible(newHost.Version) || newHost.TrafficKeyPublic == nil {		err := fmt.Errorf("incompatible netclient")		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))		return	}	key, keyErr := logic.RetrievePublicTrafficKey()	if keyErr != nil {		logger.Log(0, "error retrieving key:", keyErr.Error())		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))		return	}	// use the token	if ok := logic.TryToUseEnrollmentKey(enrollmentKey); !ok {		logger.Log(0, "host", newHost.ID.String(), newHost.Name, "failed registration")		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("invalid enrollment key"), "badrequest"))		return	}	if !hostExists {		// register host		logic.CheckHostPorts(&newHost)		if err = logic.CreateHost(&newHost); err != nil {			logger.Log(0, "host", newHost.ID.String(), newHost.Name, "failed registration -", err.Error())			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))			return		}	} else {		// need to revise the list of networks from key		// based on the ones host currently has		var networksToAdd = []string{}		currentNets := logic.GetHostNetworks(newHost.ID.String())		for _, newNet := range enrollmentKey.Networks {			if !logic.StringSliceContains(currentNets, newNet) {				networksToAdd = append(networksToAdd, newNet)			}		}		enrollmentKey.Networks = networksToAdd	}	// ready the response	server := servercfg.GetServerInfo()	server.TrafficKey = key	response := models.RegisterResponse{		ServerConf:    server,		RequestedHost: newHost,	}	logger.Log(0, newHost.Name, newHost.ID.String(), "registered with Netmaker")	w.WriteHeader(http.StatusOK)	json.NewEncoder(w).Encode(&response)	// notify host of changes, peer and node updates	go checkNetRegAndHostUpdate(enrollmentKey.Networks, &newHost)}// run through networks and send a host updatefunc checkNetRegAndHostUpdate(networks []string, h *models.Host) {	// publish host update through MQ	for i := range networks {		network := networks[i]		if ok, _ := logic.NetworkExists(network); ok {			newNode, err := logic.UpdateHostNetwork(h, network, true)			if err != nil {				logger.Log(0, "failed to add host to network:", h.ID.String(), h.Name, network, err.Error())				continue			}			logger.Log(1, "added new node", newNode.ID.String(), "to host", h.Name)			hostactions.AddAction(models.HostUpdate{				Action: models.JoinHostToNetwork,				Host:   *h,				Node:   *newNode,			})		}	}	if servercfg.IsMessageQueueBackend() {		mq.HostUpdate(&models.HostUpdate{			Action: models.RequestAck,			Host:   *h,		})		if err := mq.PublishPeerUpdate(); err != nil {			logger.Log(0, "failed to publish peer update during registration -", err.Error())		}	}}
 |