add validation for node.Address

This commit is contained in:
Matthew R Kasun
2021-04-25 08:18:43 -04:00
parent ae826002cd
commit e40712063c
7 changed files with 155 additions and 168 deletions

View File

@@ -62,6 +62,11 @@ func ValidateNode(operation string, networkName string, node models.Node) error
v := validator.New() v := validator.New()
_ = v.RegisterValidation("address_check", func(fl validator.FieldLevel) bool {
isIpv4 := functions.IsIpv4Net(node.Address)
notEmptyCheck := node.Address != ""
return (notEmptyCheck && isIpv4)
})
_ = v.RegisterValidation("endpoint_check", func(fl validator.FieldLevel) bool { _ = v.RegisterValidation("endpoint_check", func(fl validator.FieldLevel) bool {
//var isFieldUnique bool = functions.IsFieldUnique(networkName, "endpoint", node.Endpoint) //var isFieldUnique bool = functions.IsFieldUnique(networkName, "endpoint", node.Endpoint)
isIpv4 := functions.IsIpv4Net(node.Endpoint) isIpv4 := functions.IsIpv4Net(node.Endpoint)
@@ -193,6 +198,7 @@ func UpdateNode(nodechange models.Node, node models.Node) (models.Node, error) {
// prepare update model. // prepare update model.
update := bson.D{ update := bson.D{
{"$set", bson.D{ {"$set", bson.D{
{"address", node.Address},
{"name", node.Name}, {"name", node.Name},
{"password", node.Password}, {"password", node.Password},
{"listenport", node.ListenPort}, {"listenport", node.ListenPort},
@@ -212,7 +218,6 @@ func UpdateNode(nodechange models.Node, node models.Node) (models.Node, error) {
}}, }},
} }
var nodeupdate models.Node var nodeupdate models.Node
errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate) errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
if errN != nil { if errN != nil {
return nodeupdate, errN return nodeupdate, errN

View File

@@ -765,7 +765,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
if nodechange.MacAddress == "" { if nodechange.MacAddress == "" {
nodechange.MacAddress = node.MacAddress nodechange.MacAddress = node.MacAddress
} }
err = ValidateNode("update", params["network"], nodechange) err = ValidateNode("update", params["network"], nodechange)
if err != nil { if err != nil {
returnErrorResponse(w, r, formatError(err, "badrequest")) returnErrorResponse(w, r, formatError(err, "badrequest"))

View File

@@ -1,13 +1,14 @@
package models package models
import ( import (
"go.mongodb.org/mongo-driver/bson/primitive"
"github.com/gravitl/netmaker/mongoconn"
"math/rand"
"time"
"net"
"context" "context"
"math/rand"
"net"
"time"
"github.com/gravitl/netmaker/mongoconn"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
) )
const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
@@ -18,7 +19,7 @@ var seededRand *rand.Rand = rand.New(
//node struct //node struct
type Node struct { type Node struct {
ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"` ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
Address string `json:"address" bson:"address"` Address string `json:"address" bson:"address" validate:"address_check"`
LocalAddress string `json:"localaddress" bson:"localaddress" validate:"localaddress_check"` LocalAddress string `json:"localaddress" bson:"localaddress" validate:"localaddress_check"`
Name string `json:"name" bson:"name" validate:"omitempty,name_valid,max=12"` Name string `json:"name" bson:"name" validate:"omitempty,name_valid,max=12"`
ListenPort int32 `json:"listenport" bson:"listenport" validate:"omitempty,numeric,min=1024,max=65535"` ListenPort int32 `json:"listenport" bson:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
@@ -46,7 +47,6 @@ type Node struct {
PostChanges string `json:"postchanges" bson:"postchanges"` PostChanges string `json:"postchanges" bson:"postchanges"`
} }
//TODO: Contains a fatal error return. Need to change //TODO: Contains a fatal error return. Need to change
//Used in contexts where it's not the Parent network. //Used in contexts where it's not the Parent network.
func (node *Node) GetNetwork() (Network, error) { func (node *Node) GetNetwork() (Network, error) {
@@ -71,7 +71,6 @@ func(node *Node) GetNetwork() (Network, error){
return network, err return network, err
} }
//TODO: //TODO:
//Not sure if below two methods are necessary. May want to revisit //Not sure if below two methods are necessary. May want to revisit
func (node *Node) SetLastModified() { func (node *Node) SetLastModified() {
@@ -90,7 +89,6 @@ func(node *Node) SetExpirationDateTime(){
node.ExpirationDateTime = time.Unix(33174902665, 0).Unix() node.ExpirationDateTime = time.Unix(33174902665, 0).Unix()
} }
func (node *Node) SetDefaultName() { func (node *Node) SetDefaultName() {
if node.Name == "" { if node.Name == "" {
nodeid := StringWithCharset(5, charset) nodeid := StringWithCharset(5, charset)
@@ -149,4 +147,3 @@ func StringWithCharset(length int, charset string) string {
func IsIpv4Net(host string) bool { func IsIpv4Net(host string) bool {
return net.ParseIP(host) != nil return net.ParseIP(host) != nil
} }

View File

@@ -17,11 +17,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type databaseError struct {
Inner *int
Errors int
}
//should be use models.SuccessResponse and models.SuccessfulUserLoginResponse //should be use models.SuccessResponse and models.SuccessfulUserLoginResponse
//rather than creating new type but having trouble decoding that way //rather than creating new type but having trouble decoding that way
type Auth struct { type Auth struct {
@@ -96,7 +91,6 @@ func api(t *testing.T, data interface{}, method, url, authorization string) (*ht
request.Header.Set("authorization", "Bearer "+authorization) request.Header.Set("authorization", "Bearer "+authorization)
} }
client := http.Client{} client := http.Client{}
//t.Log("api request", request)
return client.Do(request) return client.Do(request)
} }
@@ -198,28 +192,6 @@ func deleteKey(t *testing.T, key, network string) {
//assert.Equal(t, int64(1), message.DeletedCount) //assert.Equal(t, int64(1), message.DeletedCount)
} }
func networkExists(t *testing.T) bool {
response, err := api(t, "", http.MethodGet, baseURL+"/api/networks", "secretkey")
assert.Nil(t, err, err)
defer response.Body.Close()
assert.Equal(t, http.StatusOK, response.StatusCode)
err = json.NewDecoder(response.Body).Decode(&Networks)
assert.Nil(t, err, err)
for i, network := range Networks {
t.Log(i, network)
if network.NetID == "" {
return false
} else {
return true
}
}
return false
}
func TestJunk(t *testing.T) {
deleteNetworks(t)
}
func deleteNetworks(t *testing.T) { func deleteNetworks(t *testing.T) {
//delete all node //delete all node
deleteAllNodes(t) deleteAllNodes(t)
@@ -237,21 +209,6 @@ func deleteNetworks(t *testing.T) {
} }
} }
func getNetworkNodes(t *testing.T) []models.ReturnNode {
var nodes []models.ReturnNode
//var node models.ReturnNode
//response, err := api(t, "", http.MethodGet, baseURL+"/api/nodes/skynet", "secretkey")
//assert.Nil(t, err, err)
//assert.Equal(t, http.StatusOK, response.StatusCode)
//defer response.Body.Close()
//err = json.NewDecoder(response.Body).Decode(&nodes)
//assert.Nil(t, err, err)
//for _, nodes := range nodes {
// nodes = append(nodes, node)
//}
return nodes
}
func deleteNode(t *testing.T) { func deleteNode(t *testing.T) {
response, err := api(t, "", http.MethodDelete, baseURL+"/api/nodes/skynet/01:02:03:04:05:06", "secretkey") response, err := api(t, "", http.MethodDelete, baseURL+"/api/nodes/skynet/01:02:03:04:05:06", "secretkey")
assert.Nil(t, err, err) assert.Nil(t, err, err)
@@ -273,6 +230,7 @@ func deleteAllNodes(t *testing.T) {
func createNode(t *testing.T) { func createNode(t *testing.T) {
var node models.Node var node models.Node
key := createAccessKey(t) key := createAccessKey(t)
node.Address = "10.71.0.1"
node.AccessKey = key.Value node.AccessKey = key.Value
node.MacAddress = "01:02:03:04:05:06" node.MacAddress = "01:02:03:04:05:06"
node.Name = "myNode" node.Name = "myNode"
@@ -296,6 +254,17 @@ func getNode(t *testing.T) models.Node {
return node return node
} }
func getNetwork(t *testing.T, network string) models.Network {
var net models.Network
response, err := api(t, "", http.MethodGet, baseURL+"/api/networks/"+network, "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&net)
assert.Nil(t, err, err)
return net
}
func setup(t *testing.T) { func setup(t *testing.T) {
deleteNetworks(t) deleteNetworks(t)
createNetwork(t) createNetwork(t)

View File

@@ -5,6 +5,7 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"testing" "testing"
"time"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -15,9 +16,7 @@ func TestCreateNetwork(t *testing.T) {
network := models.Network{} network := models.Network{}
network.NetID = "skynet" network.NetID = "skynet"
network.AddressRange = "10.71.0.0/16" network.AddressRange = "10.71.0.0/16"
if networkExists(t) {
deleteNetworks(t) deleteNetworks(t)
}
t.Run("InvalidToken", func(t *testing.T) { t.Run("InvalidToken", func(t *testing.T) {
response, err := api(t, network, http.MethodPost, baseURL+"/api/networks", "badkey") response, err := api(t, network, http.MethodPost, baseURL+"/api/networks", "badkey")
assert.Nil(t, err, err) assert.Nil(t, err, err)
@@ -140,8 +139,6 @@ func TestDeleteNetwork(t *testing.T) {
}) })
t.Run("NodesExist", func(t *testing.T) { t.Run("NodesExist", func(t *testing.T) {
setup(t) setup(t)
node := getNode(t)
t.Log(node)
response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/skynet", "secretkey") response, err := api(t, "", http.MethodDelete, baseURL+"/api/networks/skynet", "secretkey")
assert.Nil(t, err, err) assert.Nil(t, err, err)
assert.Equal(t, http.StatusForbidden, response.StatusCode) assert.Equal(t, http.StatusForbidden, response.StatusCode)
@@ -523,7 +520,7 @@ func TestUpdateNetwork(t *testing.T) {
DefaultKeepAlive int32 DefaultKeepAlive int32
} }
var network Network var network Network
network.DefaultKeepAlive = 1001 network.DefaultKeepAlive = 2000
response, err := api(t, network, http.MethodPut, baseURL+"/api/networks/skynet", "secretkey") response, err := api(t, network, http.MethodPut, baseURL+"/api/networks/skynet", "secretkey")
assert.Nil(t, err, err) assert.Nil(t, err, err)
var message models.ErrorResponse var message models.ErrorResponse
@@ -534,21 +531,26 @@ func TestUpdateNetwork(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, response.StatusCode) assert.Equal(t, http.StatusBadRequest, response.StatusCode)
}) })
t.Run("UpdateSaveConfig", func(t *testing.T) { t.Run("UpdateSaveConfig", func(t *testing.T) {
t.Skip() //t.Skip()
//does not appear to be updatable //not updatable, ensure attempt to change does not result in change
type Network struct { type Network struct {
DefaultSaveConfig *bool DefaultSaveConfig *bool
} }
var network Network var network Network
value := false var value bool
oldnet := getNetwork(t, "skynet")
if *oldnet.DefaultSaveConfig == true {
value = false
} else {
value = true
}
network.DefaultSaveConfig = &value network.DefaultSaveConfig = &value
response, err := api(t, network, http.MethodPut, baseURL+"/api/networks/skynet", "secretkey") response, err := api(t, network, http.MethodPut, baseURL+"/api/networks/skynet", "secretkey")
assert.Nil(t, err, err) assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode) assert.Equal(t, http.StatusOK, response.StatusCode)
defer response.Body.Close() newnet := getNetwork(t, "skynet")
err = json.NewDecoder(response.Body).Decode(&returnedNetwork) assert.Equal(t, oldnet.DefaultSaveConfig, newnet.DefaultSaveConfig)
assert.Nil(t, err, err)
assert.Equal(t, *network.DefaultSaveConfig, *returnedNetwork.DefaultSaveConfig)
}) })
t.Run("UpdateManualSignUP", func(t *testing.T) { t.Run("UpdateManualSignUP", func(t *testing.T) {
type Network struct { type Network struct {
@@ -612,3 +614,15 @@ func TestUpdateNetwork(t *testing.T) {
assert.Equal(t, network.DefaultListenPort, returnedNetwork.DefaultListenPort) assert.Equal(t, network.DefaultListenPort, returnedNetwork.DefaultListenPort)
}) })
} }
func TestKeyUpdate(t *testing.T) {
//get current network settings
oldnet := getNetwork(t, "skynet")
//update key
time.Sleep(time.Second * 1)
reply, err := api(t, "", http.MethodPost, baseURL+"/api/networks/skynet/keyupdate", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, reply.StatusCode)
newnet := getNetwork(t, "skynet")
assert.Greater(t, newnet.KeyUpdateTimeStamp, oldnet.KeyUpdateTimeStamp)
}

View File

@@ -104,6 +104,7 @@ func TestUpdateNode(t *testing.T) {
setup(t) setup(t)
t.Run("UpdateMulti", func(t *testing.T) { t.Run("UpdateMulti", func(t *testing.T) {
data.Address = "10.1.0.2"
data.MacAddress = "01:02:03:04:05:05" data.MacAddress = "01:02:03:04:05:05"
data.Name = "NewName" data.Name = "NewName"
data.PublicKey = "DM5qhLAE20PG9BbfBCgfr+Ac9D2NDOwCtY1rbYDLf34=" data.PublicKey = "DM5qhLAE20PG9BbfBCgfr+Ac9D2NDOwCtY1rbYDLf34="
@@ -115,7 +116,6 @@ func TestUpdateNode(t *testing.T) {
assert.Equal(t, http.StatusOK, response.StatusCode) assert.Equal(t, http.StatusOK, response.StatusCode)
defer response.Body.Close() defer response.Body.Close()
var node models.Node var node models.Node
t.Log(response.Body)
err = json.NewDecoder(response.Body).Decode(&node) err = json.NewDecoder(response.Body).Decode(&node)
assert.Nil(t, err, err) assert.Nil(t, err, err)
assert.Equal(t, data.Name, node.Name) assert.Equal(t, data.Name, node.Name)
@@ -125,6 +125,19 @@ func TestUpdateNode(t *testing.T) {
assert.Equal(t, data.LocalAddress, node.LocalAddress) assert.Equal(t, data.LocalAddress, node.LocalAddress)
assert.Equal(t, data.Endpoint, node.Endpoint) assert.Equal(t, data.Endpoint, node.Endpoint)
}) })
t.Run("InvalidAddress", func(t *testing.T) {
data.Address = "10.300.2.0"
response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:05", "secretkey")
assert.Nil(t, err, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)
var message models.ErrorResponse
defer response.Body.Close()
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 'Address' failed")
})
t.Run("InvalidMacAddress", func(t *testing.T) { t.Run("InvalidMacAddress", func(t *testing.T) {
data.MacAddress = "10:11:12:13:14:15:16" data.MacAddress = "10:11:12:13:14:15:16"
response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:05", "secretkey") response, err := api(t, data, http.MethodPut, baseURL+"/api/nodes/skynet/01:02:03:04:05:05", "secretkey")
@@ -226,7 +239,6 @@ func TestDeleteNode(t *testing.T) {
assert.Nil(t, err, err) assert.Nil(t, err, err)
assert.Equal(t, "01:02:03:04:05:06 deleted.", message.Message) assert.Equal(t, "01:02:03:04:05:06 deleted.", message.Message)
assert.Equal(t, http.StatusOK, message.Code) assert.Equal(t, http.StatusOK, message.Code)
t.Log(response.Header.Get("Content-Type"))
}) })
t.Run("NonExistantNode", func(t *testing.T) { t.Run("NonExistantNode", func(t *testing.T) {
response, err := api(t, "", http.MethodDelete, baseURL+"/api/nodes/skynet/01:02:03:04:05:06", "secretkey") response, err := api(t, "", http.MethodDelete, baseURL+"/api/nodes/skynet/01:02:03:04:05:06", "secretkey")
@@ -335,7 +347,6 @@ func TestUncordonNode(t *testing.T) {
err = json.NewDecoder(response.Body).Decode(&message) err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err) assert.Nil(t, err, err)
assert.Equal(t, "SUCCESS", message) assert.Equal(t, "SUCCESS", message)
t.Log(message, string(message))
} }
func TestCreateNode(t *testing.T) { func TestCreateNode(t *testing.T) {
@@ -525,9 +536,7 @@ func TestCreateNode(t *testing.T) {
err = json.NewDecoder(response.Body).Decode(&message) err = json.NewDecoder(response.Body).Decode(&message)
assert.Nil(t, err, err) assert.Nil(t, err, err)
assert.Equal(t, node.Name, message.Name) assert.Equal(t, node.Name, message.Name)
t.Log(message)
}) })
} }
func TestGetLastModified(t *testing.T) { func TestGetLastModified(t *testing.T) {

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"io/ioutil"
"net/http" "net/http"
"testing" "testing"
@@ -28,8 +27,6 @@ func TestAdminCreation(t *testing.T) {
assert.Equal(t, true, user.IsAdmin) assert.Equal(t, true, user.IsAdmin)
assert.Equal(t, http.StatusOK, response.StatusCode) assert.Equal(t, http.StatusOK, response.StatusCode)
assert.True(t, adminExists(t), "Admin creation failed") assert.True(t, adminExists(t), "Admin creation failed")
message, _ := ioutil.ReadAll(response.Body)
t.Log(string(message))
}) })
t.Run("AdminCreationFailure", func(t *testing.T) { t.Run("AdminCreationFailure", func(t *testing.T) {
if !adminExists(t) { if !adminExists(t) {
@@ -50,10 +47,7 @@ func TestAdminCreation(t *testing.T) {
func TestGetUser(t *testing.T) { func TestGetUser(t *testing.T) {
if !adminExists(t) { if !adminExists(t) {
t.Log("no admin - creating")
addAdmin(t) addAdmin(t)
} else {
t.Log("admin exists")
} }
t.Run("GetUserWithValidToken", func(t *testing.T) { t.Run("GetUserWithValidToken", func(t *testing.T) {
token, err := authenticate(t) token, err := authenticate(t)