rove/cmd/rove-server-rest-proxy/http_test.go
Marc Di Luzio 92222127a6 Add basic account security
This adds a secret token associated with each account

	The token must then be sent with follow-up requests to ensure they get accepted

	This is _very_ basic security, and without TLS is completely vulnerable to MITM attacks, as well as brute force guessing (though it'd take a while to guess the a correct UUID)
2020-07-07 22:20:23 +01:00

150 lines
4.2 KiB
Go

// +build integration
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"testing"
"github.com/google/uuid"
"github.com/mdiluz/rove/pkg/rove"
"github.com/stretchr/testify/assert"
)
// Server is a simple wrapper to a server path
type Server string
// Request performs a HTTP
func (s Server) Request(method, path string, in, out interface{}) error {
u := url.URL{
Scheme: "http",
Host: fmt.Sprintf("%s:8080", string(s)),
Path: path,
}
client := &http.Client{}
// Marshal the input
marshalled, err := json.Marshal(in)
if err != nil {
return err
}
// Set up the request
req, err := http.NewRequest(method, u.String(), bytes.NewReader(marshalled))
if err != nil {
return err
}
// Do the POST
req.Header.Set("Content-Type", "application/json")
if resp, err := client.Do(req); err != nil {
return err
} else if resp.StatusCode != http.StatusOK {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body to code %d", resp.StatusCode)
}
return fmt.Errorf("http returned status %d: %s", resp.StatusCode, string(body))
} else {
return json.NewDecoder(resp.Body).Decode(out)
}
}
var serv = Server(os.Getenv("ROVE_HTTP"))
func TestServer_ServerStatus(t *testing.T) {
req := &rove.ServerStatusRequest{}
resp := &rove.ServerStatusResponse{}
if err := serv.Request("GET", "server-status", req, resp); err != nil {
log.Fatal(err)
}
}
func TestServer_Register(t *testing.T) {
req := &rove.RegisterRequest{Name: uuid.New().String()}
resp := &rove.RegisterResponse{}
err := serv.Request("POST", "register", req, resp)
assert.NoError(t, err, "First register attempt should pass")
err = serv.Request("POST", "register", req, resp)
assert.Error(t, err, "Second identical register attempt should fail")
}
func TestServer_Command(t *testing.T) {
acc := uuid.New().String()
var resp rove.RegisterResponse
err := serv.Request("POST", "register", &rove.RegisterRequest{Name: acc}, &resp)
assert.NoError(t, err, "First register attempt should pass")
req := &rove.CommandRequest{
Account: &rove.Account{
Name: resp.Account.Name,
},
Commands: []*rove.Command{
{
Command: "move",
Bearing: "NE",
},
},
}
assert.Error(t, serv.Request("POST", "command", req, &rove.CommandResponse{}), "Commands should fail with no secret")
req.Account.Secret = resp.Account.Secret
assert.NoError(t, serv.Request("POST", "command", req, &rove.CommandResponse{}), "Commands should pass")
}
func TestServer_Radar(t *testing.T) {
acc := uuid.New().String()
var reg rove.RegisterResponse
err := serv.Request("POST", "register", &rove.RegisterRequest{Name: acc}, &reg)
assert.NoError(t, err, "First register attempt should pass")
resp := &rove.RadarResponse{}
req := &rove.RadarRequest{
Account: &rove.Account{
Name: reg.Account.Name,
},
}
assert.Error(t, serv.Request("POST", "radar", req, resp), "Radar should fail without secret")
req.Account.Secret = reg.Account.Secret
assert.NoError(t, serv.Request("POST", "radar", req, resp), "Radar should pass")
assert.NotZero(t, resp.Range, "Radar should return valid range")
w := int(resp.Range*2 + 1)
assert.Equal(t, w*w, len(resp.Tiles), "radar should return correct number of tiles")
assert.Equal(t, w*w, len(resp.Objects), "radar should return correct number of objects")
}
func TestServer_Status(t *testing.T) {
acc := uuid.New().String()
var reg rove.RegisterResponse
err := serv.Request("POST", "register", &rove.RegisterRequest{Name: acc}, &reg)
assert.NoError(t, err, "First register attempt should pass")
resp := &rove.StatusResponse{}
req := &rove.StatusRequest{
Account: &rove.Account{
Name: reg.Account.Name,
},
}
assert.Error(t, serv.Request("POST", "status", req, resp), "Status should fail without secret")
req.Account.Secret = reg.Account.Secret
assert.NoError(t, serv.Request("POST", "status", req, resp), "Status should pass")
assert.NotZero(t, resp.Range, "Rover should return valid range")
assert.NotZero(t, len(resp.Name), "Rover should return valid name")
assert.NotZero(t, resp.Position, "Rover should return valid position")
assert.NotZero(t, resp.Integrity, "Rover should have positive integrity")
}