diff --git a/controllers/networkHttpController.go b/controllers/networkHttpController.go index 0d849302..431c2e86 100644 --- a/controllers/networkHttpController.go +++ b/controllers/networkHttpController.go @@ -186,23 +186,11 @@ func ValidateNetworkCreate(network models.Network) error { //Simple get network function func getNetwork(w http.ResponseWriter, r *http.Request) { - // set header. w.Header().Set("Content-Type", "application/json") - var params = mux.Vars(r) - - var network models.Network - - collection := mongoconn.Client.Database("netmaker").Collection("networks") - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - - filter := bson.M{"netid": params["networkname"]} - err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&network) - - defer cancel() - + netname := params["networkname"] + network, err := GetNetwork(netname) if err != nil { returnErrorResponse(w, r, formatError(err, "internal")) return @@ -211,27 +199,41 @@ func getNetwork(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(network) } -func keyUpdate(w http.ResponseWriter, r *http.Request) { - - w.Header().Set("Content-Type", "application/json") - - var params = mux.Vars(r) - +func GetNetwork(name string) (models.Network, error) { var network models.Network + collection := mongoconn.Client.Database("netmaker").Collection("networks") + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + filter := bson.M{"netid": name} + err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&network) + defer cancel() + if err != nil { + return models.Network{}, err + } + return network, nil +} - network, err := functions.GetParentNetwork(params["networkname"]) +func keyUpdate(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + var params = mux.Vars(r) + netname := params["networkname"] + network, err := KeyUpdate(netname) if err != nil { returnErrorResponse(w, r, formatError(err, "internal")) return } + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(network) +} +func KeyUpdate(netname string) (models.Network, error) { + network, err := functions.GetParentNetwork(netname) + if err != nil { + return models.Network{}, err + } network.KeyUpdateTimeStamp = time.Now().Unix() - collection := mongoconn.Client.Database("netmaker").Collection("networks") - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - - filter := bson.M{"netid": params["networkname"]} + filter := bson.M{"netid": netname} // prepare update model. update := bson.D{ {"$set", bson.D{ @@ -251,18 +253,12 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) { {"checkininterval", network.DefaultCheckInInterval}, }}, } - err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network) - defer cancel() - if err != nil { - returnErrorResponse(w, r, formatError(err, "internal")) - return + return models.Network{}, err } - - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(network) + return network, nil } //Update a network @@ -562,8 +558,7 @@ func CreateNetwork(network models.Network) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) // insert our network into the network table - result, err := collection.InsertOne(ctx, network) - fmt.Printf("=========%T, %v\n", result, result) + _, err = collection.InsertOne(ctx, network) defer cancel() if err != nil { return err @@ -576,188 +571,167 @@ func CreateNetwork(network models.Network) error { //TODO: Very little error handling //accesskey is created as a json string inside the Network collection item in mongo func createAccessKey(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - var params = mux.Vars(r) - - var network models.Network var accesskey models.AccessKey - //start here network, err := functions.GetParentNetwork(params["networkname"]) if err != nil { returnErrorResponse(w, r, formatError(err, "internal")) return } - err = json.NewDecoder(r.Body).Decode(&accesskey) if err != nil { returnErrorResponse(w, r, formatError(err, "internal")) return } + key, err := CreateAccessKey(accesskey, network) + if err != nil { + returnErrorResponse(w, r, formatError(err, "badrequest")) + return + } + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(key) + //w.Write([]byte(accesskey.AccessString)) +} +func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models.AccessKey, error) { if accesskey.Name == "" { accesskey.Name = functions.GenKeyName() } if accesskey.Value == "" { accesskey.Value = functions.GenKey() } - if accesskey.Uses == 0 { accesskey.Uses = 1 } + for _, key := range network.AccessKeys { + if key.Name == accesskey.Name { + return models.AccessKey{}, errors.New("Duplicate AccessKey Name") + } + } + _, gconf, err := functions.GetGlobalConfig() if err != nil { - returnErrorResponse(w, r, formatError(err, "internal")) - return + //returnErrorResponse(w, r, formatError(err, "internal")) + return models.AccessKey{}, err } - privAddr := "" - if *network.IsLocal { - privAddr = network.LocalRange + if network.IsLocal != nil { + if *network.IsLocal { + privAddr = network.LocalRange + } } - netID := params["networkname"] + //netID := params["networkname"] address := gconf.ServerGRPC + gconf.PortGRPC - - accessstringdec := address + "|" + netID + "|" + accesskey.Value + "|" + privAddr + accessstringdec := address + "|" + network.NetID + "|" + accesskey.Value + "|" + privAddr accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(accessstringdec)) - + //validate accesskey + v := validator.New() + err = v.Struct(accesskey) + if err != nil { + for _, e := range err.(validator.ValidationErrors) { + fmt.Println(e) + } + return models.AccessKey{}, err + } network.AccessKeys = append(network.AccessKeys, accesskey) - collection := mongoconn.Client.Database("netmaker").Collection("networks") - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - // Create filter - filter := bson.M{"netid": params["networkname"]} - + filter := bson.M{"netid": network.NetID} // Read update model from body request fmt.Println("Adding key to " + network.NetID) - // prepare update model. update := bson.D{ {"$set", bson.D{ {"accesskeys", network.AccessKeys}, }}, } - err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network) - defer cancel() - if err != nil { - returnErrorResponse(w, r, formatError(err, "internal")) - return + //returnErrorResponse(w, r, formatError(err, "internal")) + return models.AccessKey{}, err } - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(accesskey) - //w.Write([]byte(accesskey.AccessString)) + return accesskey, nil } //pretty simple get func getAccessKeys(w http.ResponseWriter, r *http.Request) { - - // set header. w.Header().Set("Content-Type", "application/json") - var params = mux.Vars(r) - - var network models.Network - //var keys []models.DisplayKey - var keys []models.AccessKey - collection := mongoconn.Client.Database("netmaker").Collection("networks") - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - - filter := bson.M{"netid": params["networkname"]} - err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&network) - - defer cancel() - + network := params["networkname"] + keys, err := GetKeys(network) if err != nil { returnErrorResponse(w, r, formatError(err, "internal")) return } - keydata, err := json.Marshal(network.AccessKeys) - - if err != nil { - returnErrorResponse(w, r, formatError(err, "internal")) - return - } - - json.Unmarshal(keydata, &keys) - w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(keys) } +func GetKeys(net string) ([]models.AccessKey, error) { + + var network models.Network + collection := mongoconn.Client.Database("netmaker").Collection("networks") + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + filter := bson.M{"netid": net} + err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&network) + defer cancel() + if err != nil { + return []models.AccessKey{}, err + } + return network.AccessKeys, nil +} //delete key. Has to do a little funky logic since it's not a collection item func deleteAccessKey(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - var params = mux.Vars(r) - - var network models.Network keyname := params["name"] - - //start here - network, err := functions.GetParentNetwork(params["networkname"]) + netname := params["networkname"] + err := DeleteKey(keyname, netname) if err != nil { - returnErrorResponse(w, r, formatError(err, "internal")) + returnErrorResponse(w, r, formatError(err, "badrequest")) return } + w.WriteHeader(http.StatusOK) +} +func DeleteKey(keyname, netname string) error { + network, err := functions.GetParentNetwork(netname) + if err != nil { + return err + } //basically, turn the list of access keys into the list of access keys before and after the item //have not done any error handling for if there's like...1 item. I think it works? need to test. found := false - for i := len(network.AccessKeys) - 1; i >= 0; i-- { - - currentkey := network.AccessKeys[i] + var updatedKeys []models.AccessKey + for _, currentkey := range network.AccessKeys { if currentkey.Name == keyname { - network.AccessKeys = append(network.AccessKeys[:i], - network.AccessKeys[i+1:]...) found = true + } else { + updatedKeys = append(updatedKeys, currentkey) } } if !found { - err = errors.New("key " + keyname + " does not exist") - returnErrorResponse(w, r, formatError(err, "badrequest")) - return + return errors.New("key " + keyname + " does not exist") } collection := mongoconn.Client.Database("netmaker").Collection("networks") - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - // Create filter - filter := bson.M{"netid": params["networkname"]} - + filter := bson.M{"netid": netname} // prepare update model. update := bson.D{ {"$set", bson.D{ - {"accesskeys", network.AccessKeys}, + {"accesskeys", updatedKeys}, }}, } - err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network) - defer cancel() - if err != nil { - returnErrorResponse(w, r, formatError(err, "internal")) - return + return err } - var keys []models.AccessKey - keydata, err := json.Marshal(network.AccessKeys) - if err != nil { - returnErrorResponse(w, r, formatError(err, "internal")) - return - } - - json.Unmarshal(keydata, &keys) - - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(keys) + return nil } diff --git a/controllers/networkHttpController_test.go b/controllers/networkHttpController_test.go index f8c40d34..b5a1fc9a 100644 --- a/controllers/networkHttpController_test.go +++ b/controllers/networkHttpController_test.go @@ -2,6 +2,7 @@ package controller import ( "testing" + "time" "github.com/gravitl/netmaker/models" "github.com/stretchr/testify/assert" @@ -13,24 +14,195 @@ type NetworkValidationTestCase struct { errMessage string } +func deleteNet() { + _, err := GetNetwork("skynet") + if err == nil { + _, _ = DeleteNetwork("skynet") + } +} + +func createNet() { + var network models.Network + network.NetID = "skynet" + network.AddressRange = "10.0.0.1/24" + network.DisplayName = "mynetwork" + _, err := GetNetwork("skynet") + if err != nil { + CreateNetwork(network) + } +} + func TestGetNetworks(t *testing.T) { - //calls functions.ListNetworks --- nothing to be don + //calls functions.ListNetworks --- nothing to be done } func TestCreateNetwork(t *testing.T) { + deleteNet() + var network models.Network + network.NetID = "skynet" + network.AddressRange = "10.0.0.1/24" + network.DisplayName = "mynetwork" + err := CreateNetwork(network) + assert.Nil(t, err) +} +func TestGetDeleteNetwork(t *testing.T) { + createNet() + //create nodes + t.Run("NetworkwithNodes", func(t *testing.T) { + }) + t.Run("GetExistingNetwork", func(t *testing.T) { + network, err := GetNetwork("skynet") + assert.Nil(t, err) + assert.Equal(t, "skynet", network.NetID) + }) + t.Run("DeleteExistingNetwork", func(t *testing.T) { + result, err := DeleteNetwork("skynet") + assert.Nil(t, err) + assert.Equal(t, int64(1), result.DeletedCount) + t.Log(result.DeletedCount) + }) + t.Run("GetNonExistantNetwork", func(t *testing.T) { + network, err := GetNetwork("skynet") + assert.NotNil(t, err) + assert.Equal(t, "mongo: no documents in result", err.Error()) + assert.Equal(t, "", network.NetID) + }) + t.Run("NonExistantNetwork", func(t *testing.T) { + result, err := DeleteNetwork("skynet") + assert.Nil(t, err) + assert.Equal(t, int64(0), result.DeletedCount) + t.Log(result.DeletedCount) + }) } func TestGetNetwork(t *testing.T) { } func TestUpdateNetwork(t *testing.T) { } -func TestDeleteNetwork(t *testing.T) { -} + func TestKeyUpdate(t *testing.T) { + createNet() + existing, err := GetNetwork("skynet") + assert.Nil(t, err) + time.Sleep(time.Second * 1) + network, err := KeyUpdate("skynet") + assert.Nil(t, err) + network, err = GetNetwork("skynet") + assert.Nil(t, err) + assert.Greater(t, network.KeyUpdateTimeStamp, existing.KeyUpdateTimeStamp) } + func TestCreateKey(t *testing.T) { + createNet() + var accesskey models.AccessKey + var network models.Network + network.NetID = "skynet" + t.Run("InvalidName", func(t *testing.T) { + network, err := GetNetwork("skynet") + assert.Nil(t, err) + accesskey.Name = "bad-name" + _, err = CreateAccessKey(accesskey, network) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'alphanum' tag") + }) + t.Run("NameTooLong", func(t *testing.T) { + network, err := GetNetwork("skynet") + assert.Nil(t, err) + accesskey.Name = "Thisisareallylongkeynamethatwillfail" + _, err = CreateAccessKey(accesskey, network) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'max' tag") + }) + t.Run("BlankName", func(t *testing.T) { + network, err := GetNetwork("skynet") + assert.Nil(t, err) + accesskey.Name = "" + key, err := CreateAccessKey(accesskey, network) + assert.Nil(t, err) + assert.NotEqual(t, "", key.Name) + }) + t.Run("InvalidValue", func(t *testing.T) { + network, err := GetNetwork("skynet") + assert.Nil(t, err) + accesskey.Value = "bad-value" + _, err = CreateAccessKey(accesskey, network) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "Field validation for 'Value' failed on the 'alphanum' tag") + }) + t.Run("BlankValue", func(t *testing.T) { + network, err := GetNetwork("skynet") + assert.Nil(t, err) + accesskey.Name = "mykey" + accesskey.Value = "" + key, err := CreateAccessKey(accesskey, network) + assert.Nil(t, err) + assert.NotEqual(t, "", key.Value) + assert.Equal(t, accesskey.Name, key.Name) + }) + t.Run("ValueTooLong", func(t *testing.T) { + network, err := GetNetwork("skynet") + assert.Nil(t, err) + accesskey.Name = "keyname" + accesskey.Value = "AccessKeyValuethatistoolong" + _, err = CreateAccessKey(accesskey, network) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "Field validation for 'Value' failed on the 'max' tag") + }) + t.Run("BlankUses", func(t *testing.T) { + network, err := GetNetwork("skynet") + assert.Nil(t, err) + accesskey.Uses = 0 + accesskey.Value = "" + key, err := CreateAccessKey(accesskey, network) + assert.Nil(t, err) + assert.Equal(t, 1, key.Uses) + }) + t.Run("DuplicateKey", func(t *testing.T) { + network, err := GetNetwork("skynet") + assert.Nil(t, err) + accesskey.Name = "mykey" + _, err = CreateAccessKey(accesskey, network) + assert.NotNil(t, err) + assert.Equal(t, "Duplicate AccessKey Name", err.Error()) + }) } -func TestGetKey(t *testing.T) { +func TestGetKeys(t *testing.T) { + deleteNet() + createNet() + network, err := GetNetwork("skynet") + assert.Nil(t, err) + var key models.AccessKey + key.Name = "mykey" + _, err = CreateAccessKey(key, network) + assert.Nil(t, err) + t.Run("KeyExists", func(t *testing.T) { + keys, err := GetKeys(network.NetID) + assert.Nil(t, err) + assert.NotEqual(t, models.AccessKey{}, keys) + }) + t.Run("NonExistantKey", func(t *testing.T) { + err := DeleteKey("mykey", "skynet") + assert.Nil(t, err) + keys, err := GetKeys(network.NetID) + assert.Nil(t, err) + assert.Equal(t, []models.AccessKey(nil), keys) + }) } func TestDeleteKey(t *testing.T) { + createNet() + network, err := GetNetwork("skynet") + assert.Nil(t, err) + var key models.AccessKey + key.Name = "mykey" + _, err = CreateAccessKey(key, network) + assert.Nil(t, err) + t.Run("ExistingKey", func(t *testing.T) { + err := DeleteKey("mykey", "skynet") + assert.Nil(t, err) + }) + t.Run("NonExistantKey", func(t *testing.T) { + err := DeleteKey("mykey", "skynet") + assert.NotNil(t, err) + assert.Equal(t, "key mykey does not exist", err.Error()) + }) } func TestSecurityCheck(t *testing.T) { } @@ -39,6 +211,7 @@ func TestValidateNetworkUpdate(t *testing.T) { func TestValidateNetworkCreate(t *testing.T) { yes := true no := false + deleteNet() //DeleteNetworks cases := []NetworkValidationTestCase{ NetworkValidationTestCase{ @@ -194,10 +367,10 @@ func TestValidateNetworkCreate(t *testing.T) { } t.Run("DuplicateNetID", func(t *testing.T) { var net1, net2 models.Network - net1.NetID = "skylink" + net1.NetID = "skynet" net1.AddressRange = "10.0.0.1/24" net1.DisplayName = "mynetwork" - net2.NetID = "skylink" + net2.NetID = "skynet" net2.AddressRange = "10.0.1.1/24" net2.IsDualStack = &no diff --git a/functions/helpers.go b/functions/helpers.go index 7a9f89a9..f8bb38c3 100644 --- a/functions/helpers.go +++ b/functions/helpers.go @@ -445,17 +445,16 @@ func NameInNetworkCharSet(name string) bool { func NameInDNSCharSet(name string) bool { - charset := "abcdefghijklmnopqrstuvwxyz1234567890-." + charset := "abcdefghijklmnopqrstuvwxyz1234567890-." - for _, char := range name { - if !strings.Contains(charset, strings.ToLower(string(char))) { - return false - } - } - return true + for _, char := range name { + if !strings.Contains(charset, strings.ToLower(string(char))) { + return false + } + } + return true } - func NameInNodeCharSet(name string) bool { charset := "abcdefghijklmnopqrstuvwxyz1234567890-" @@ -528,35 +527,35 @@ func UniqueAddress(networkName string) (string, error) { func UniqueAddress6(networkName string) (string, error) { - var network models.Network - network, err := GetParentNetwork(networkName) + var network models.Network + network, err := GetParentNetwork(networkName) if !*network.IsDualStack { return "", nil } if err != nil { - fmt.Println("UniqueAddress6 encountered an error") - return "666", err - } + fmt.Println("UniqueAddress6 encountered an error") + return "666", err + } - offset := true - ip, ipnet, err := net.ParseCIDR(network.AddressRange6) - if err != nil { - fmt.Println("UniqueAddress6 encountered an error") - return "666", err - } - for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); Inc(ip) { - if offset { - offset = false - continue - } - if IsIPUnique(networkName, ip.String()) { - return ip.String(), err - } - } - //TODO - err1 := errors.New("ERROR: No unique addresses available. Check network subnet.") - return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1 + offset := true + ip, ipnet, err := net.ParseCIDR(network.AddressRange6) + if err != nil { + fmt.Println("UniqueAddress6 encountered an error") + return "666", err + } + for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); Inc(ip) { + if offset { + offset = false + continue + } + if IsIPUnique(networkName, ip.String()) { + return ip.String(), err + } + } + //TODO + err1 := errors.New("ERROR: No unique addresses available. Check network subnet.") + return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1 } //pretty simple get @@ -620,7 +619,7 @@ func GenKeyName() string { for i := range b { b[i] = charset[seededRand.Intn(len(charset))] } - return "key-" + string(b) + return "key" + string(b) } //checks if IP is unique in the address range diff --git a/models/network.go b/models/network.go index ffd91eea..0345028f 100644 --- a/models/network.go +++ b/models/network.go @@ -14,24 +14,26 @@ type Network struct { AddressRange string `json:"addressrange" bson:"addressrange" validate:"required,cidr"` // bug in validator --- required_with does not work with bools issue#683 // AddressRange6 string `json:"addressrange6" bson:"addressrange6" validate:"required_with=isdualstack true,cidrv6"` - AddressRange6 string `json:"addressrange6" bson:"addressrange6" validate:"addressrange6_valid"` - DisplayName string `json:"displayname,omitempty" bson:"displayname,omitempty" validate:"omitempty,alphanum,min=2,max=20,displayname_unique"` - NetID string `json:"netid" bson:"netid" validate:"required,alphanum,min=1,max=12,netid_valid"` - NodesLastModified int64 `json:"nodeslastmodified" bson:"nodeslastmodified"` - NetworkLastModified int64 `json:"networklastmodified" bson:"networklastmodified"` - DefaultInterface string `json:"defaultinterface" bson:"defaultinterface"` - DefaultListenPort int32 `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"` - DefaultPostUp string `json:"defaultpostup" bson:"defaultpostup"` - DefaultPostDown string `json:"defaultpostdown" bson:"defaultpostdown"` - KeyUpdateTimeStamp int64 `json:"keyupdatetimestamp" bson:"keyupdatetimestamp"` - DefaultKeepalive int32 `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"` - DefaultSaveConfig *bool `json:"defaultsaveconfig" bson:"defaultsaveconfig"` - AccessKeys []AccessKey `json:"accesskeys" bson:"accesskeys"` - AllowManualSignUp *bool `json:"allowmanualsignup" bson:"allowmanualsignup"` - IsLocal *bool `json:"islocal" bson:"islocal"` - IsDualStack *bool `json:"isdualstack" bson:"isdualstack"` - LocalRange string `json:"localrange" bson:"localrange" validate:"omitempty,cidr"` - DefaultCheckInInterval int32 `json:"checkininterval,omitempty" bson:"checkininterval,omitempty" validate:"omitempty,numeric,min=2,max=100000"` + AddressRange6 string `json:"addressrange6" bson:"addressrange6" validate:"addressrange6_valid"` + //can't have min=1 with omitempty + DisplayName string `json:"displayname,omitempty" bson:"displayname,omitempty" validate:"omitempty,alphanum,min=2,max=20,displayname_unique"` + NetID string `json:"netid" bson:"netid" validate:"required,alphanum,min=1,max=12,netid_valid"` + NodesLastModified int64 `json:"nodeslastmodified" bson:"nodeslastmodified"` + NetworkLastModified int64 `json:"networklastmodified" bson:"networklastmodified"` + DefaultInterface string `json:"defaultinterface" bson:"defaultinterface"` + DefaultListenPort int32 `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"` + DefaultPostUp string `json:"defaultpostup" bson:"defaultpostup"` + DefaultPostDown string `json:"defaultpostdown" bson:"defaultpostdown"` + KeyUpdateTimeStamp int64 `json:"keyupdatetimestamp" bson:"keyupdatetimestamp"` + DefaultKeepalive int32 `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"` + DefaultSaveConfig *bool `json:"defaultsaveconfig" bson:"defaultsaveconfig"` + AccessKeys []AccessKey `json:"accesskeys" bson:"accesskeys"` + AllowManualSignUp *bool `json:"allowmanualsignup" bson:"allowmanualsignup"` + IsLocal *bool `json:"islocal" bson:"islocal"` + IsDualStack *bool `json:"isdualstack" bson:"isdualstack"` + LocalRange string `json:"localrange" bson:"localrange" validate:"omitempty,cidr"` + //can't have min=1 with omitempty + DefaultCheckInInterval int32 `json:"checkininterval,omitempty" bson:"checkininterval,omitempty" validate:"omitempty,numeric,min=2,max=100000"` } //TODO: diff --git a/models/structs.go b/models/structs.go index 8603720d..bfdfabae 100644 --- a/models/structs.go +++ b/models/structs.go @@ -62,8 +62,8 @@ type SuccessResponse struct { } type AccessKey struct { - Name string `json:"name" bson:"name"` - Value string `json:"value" bson:"value"` + Name string `json:"name" bson:"name" validate:"omitempty,alphanum,max=20"` + Value string `json:"value" bson:"value" validate:"omitempty,alphanum,max=16"` AccessString string `json:"accessstring" bson:"accessstring"` Uses int `json:"uses" bson:"uses"` } diff --git a/test/api_test.go b/test/api_test.go index 647db459..11a77f79 100644 --- a/test/api_test.go +++ b/test/api_test.go @@ -236,7 +236,6 @@ func createNode(t *testing.T) { node.Name = "myNode" node.PublicKey = "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=" node.Password = "tobedetermined" - node.LocalAddress = "192.168.0.1" node.Endpoint = "10.100.100.4" response, err := api(t, node, http.MethodPost, "http://localhost:8081:/api/nodes/skynet", "secretkey") assert.Nil(t, err, err) diff --git a/test/network_test.go b/test/network_test.go index bcb20921..b6788626 100644 --- a/test/network_test.go +++ b/test/network_test.go @@ -141,13 +141,13 @@ func TestDeleteNetwork(t *testing.T) { setup(t) response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/skynet", "secretkey") assert.Nil(t, err, err) - assert.Equal(t, http.StatusForbidden, response.StatusCode) + assert.Equal(t, http.StatusBadRequest, response.StatusCode) defer response.Body.Close() var message models.ErrorResponse err = json.NewDecoder(response.Body).Decode(&message) assert.Nil(t, err, err) assert.Contains(t, message.Message, "Node check failed") - assert.Equal(t, http.StatusForbidden, message.Code) + assert.Equal(t, http.StatusBadRequest, message.Code) }) t.Run("ValidKey", func(t *testing.T) { type Message struct { @@ -202,11 +202,15 @@ func TestCreateKey(t *testing.T) { assert.Equal(t, 1, returnedkey.Uses) }) t.Run("DuplicateAccessKey", func(t *testing.T) { - //this is allowed I think it should fail fail response, err := api(t, key, http.MethodPost, baseURL+"/api/networks/skynet/keys", "secretkey") assert.Nil(t, err, err) - assert.Equal(t, http.StatusOK, response.StatusCode) - deleteKey(t, key.Name, "skynet") + assert.Equal(t, http.StatusBadRequest, response.StatusCode) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err) + assert.Equal(t, http.StatusBadRequest, message.Code) + assert.Equal(t, "Duplicate AccessKey Name", message.Message) }) t.Run("InvalidToken", func(t *testing.T) { @@ -239,18 +243,9 @@ func TestDeleteKey(t *testing.T) { //ensure key exists createKey(t) t.Run("KeyValid", func(t *testing.T) { - //fails -- deletecount not returned response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/skynet/keys/skynet", "secretkey") assert.Nil(t, err, err) - defer response.Body.Close() - //var message mongo.DeleteResult - var messages []models.AccessKey - err = json.NewDecoder(response.Body).Decode(&messages) - assert.Nil(t, err, err) assert.Equal(t, http.StatusOK, response.StatusCode) - for _, message := range messages { - assert.Equal(t, "skynet", message.Name) - } }) t.Run("InValidKey", func(t *testing.T) { response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/skynet/keys/badkey", "secretkey") @@ -515,7 +510,7 @@ func TestUpdateNetwork(t *testing.T) { t.Run("UpdateKeepAliveTooBig", func(t *testing.T) { //does not fails ----- value gets updated. // ----- needs fixing ----- - t.Skip() + //t.Skip() type Network struct { DefaultKeepAlive int32 } @@ -527,7 +522,7 @@ func TestUpdateNetwork(t *testing.T) { err = json.NewDecoder(response.Body).Decode(&message) assert.Nil(t, err, err) assert.Equal(t, http.StatusBadRequest, message.Code) - assert.Contains(t, message.Message, "Field validation for 'DefaultKeepAlive' failed") + assert.Contains(t, message.Message, "Field validation for 'DefaultKeepalive' failed on the 'max' tag") assert.Equal(t, http.StatusBadRequest, response.StatusCode) }) t.Run("UpdateSaveConfig", func(t *testing.T) {