Increase test coverage, mock libcurl & uniformize error messages

This commit is contained in:
Brendan LE GLAUNEC
2018-02-14 13:49:28 +01:00
committed by Brendan Le Glaunec
parent c1ea6b167c
commit 74672f6625
8 changed files with 478 additions and 203 deletions
+30 -50
View File
@@ -14,11 +14,7 @@ func doNotWrite([]uint8, interface{}) bool {
return true
}
func routeAttack(camera Stream, route string, timeout time.Duration, enableLogs bool) bool {
easy := curl.EasyInit()
defer easy.Cleanup()
if easy != nil {
func routeAttack(c Curler, camera Stream, route string, timeout time.Duration, enableLogs bool) bool {
attackURL := fmt.Sprintf(
"rtsp://%s:%s@%s:%d/%s",
camera.Username,
@@ -30,32 +26,32 @@ func routeAttack(camera Stream, route string, timeout time.Duration, enableLogs
if enableLogs {
// Debug logs when logs are enabled
easy.Setopt(curl.OPT_VERBOSE, 1)
c.Setopt(curl.OPT_VERBOSE, 1)
} else {
// Do not write sdp in stdout
easy.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite)
c.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite)
}
// Do not send a body in the describe request
easy.Setopt(curl.OPT_NOBODY, 1)
c.Setopt(curl.OPT_NOBODY, 1)
// Send a request to the URL of the camera we want to attack
easy.Setopt(curl.OPT_URL, attackURL)
c.Setopt(curl.OPT_URL, attackURL)
// Set the RTSP STREAM URI as the camera URL
easy.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
// 2 is CURL_RTSPREQ_DESCRIBE
easy.Setopt(curl.OPT_RTSP_REQUEST, 2)
c.Setopt(curl.OPT_RTSP_REQUEST, 2)
// Set custom timeout
easy.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond))
c.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond))
// Perform the request
err := easy.Perform()
err := c.Perform()
if err != nil {
fmt.Printf("\nERROR: curl timeout on camera '%s' reached after %s.\nconsider increasing the timeout (-T, --timeout parameter) to at least 5000ms if scanning an unstable network.\n", camera.Address, timeout.String())
return false
}
// Get return code for the request
rc, err := easy.Getinfo(curl.INFO_RESPONSE_CODE)
rc, err := c.Getinfo(curl.INFO_RESPONSE_CODE)
if err != nil {
return false
}
@@ -65,15 +61,10 @@ func routeAttack(camera Stream, route string, timeout time.Duration, enableLogs
if rc == 200 || rc == 401 || rc == 403 {
return true
}
}
return false
}
func credAttack(camera Stream, username string, password string, timeout time.Duration, enableLogs bool) bool {
easy := curl.EasyInit()
defer easy.Cleanup()
if easy != nil {
func credAttack(c Curler, camera Stream, username string, password string, timeout time.Duration, enableLogs bool) bool {
attackURL := fmt.Sprintf(
"rtsp://%s:%s@%s:%d/%s",
username,
@@ -85,32 +76,32 @@ func credAttack(camera Stream, username string, password string, timeout time.Du
if enableLogs {
// Debug logs when logs are enabled
easy.Setopt(curl.OPT_VERBOSE, 1)
c.Setopt(curl.OPT_VERBOSE, 1)
} else {
// Do not write sdp in stdout
easy.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite)
c.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite)
}
// Do not send a body in the describe request
easy.Setopt(curl.OPT_NOBODY, 1)
c.Setopt(curl.OPT_NOBODY, 1)
// Send a request to the URL of the camera we want to attack
easy.Setopt(curl.OPT_URL, attackURL)
c.Setopt(curl.OPT_URL, attackURL)
// Set the RTSP STREAM URI as the camera URL
easy.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
// 2 is CURL_RTSPREQ_DESCRIBE
easy.Setopt(curl.OPT_RTSP_REQUEST, 2)
c.Setopt(curl.OPT_RTSP_REQUEST, 2)
// Set custom timeout
easy.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond))
c.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond))
// Perform the request
err := easy.Perform()
err := c.Perform()
if err != nil {
fmt.Printf("\nERROR: curl timeout on camera '%s' reached after %s.\nconsider increasing the timeout (-T, --timeout parameter) to at least 5000ms if scanning an unstable network.\n", camera.Address, timeout.String())
return false
}
// Get return code for the request
rc, err := easy.Getinfo(curl.INFO_RESPONSE_CODE)
rc, err := c.Getinfo(curl.INFO_RESPONSE_CODE)
if err != nil {
return false
}
@@ -120,14 +111,13 @@ func credAttack(camera Stream, username string, password string, timeout time.Du
if rc == 200 || rc == 404 {
return true
}
}
return false
}
func attackCameraCredentials(target Stream, credentials Credentials, resultsChan chan<- Stream, timeout time.Duration, log bool) {
func attackCameraCredentials(c Curler, target Stream, credentials Credentials, resultsChan chan<- Stream, timeout time.Duration, log bool) {
for _, username := range credentials.Usernames {
for _, password := range credentials.Passwords {
ok := credAttack(target, username, password, timeout, log)
ok := credAttack(c, target, username, password, timeout, log)
if ok {
target.CredentialsFound = true
target.Username = username
@@ -141,9 +131,9 @@ func attackCameraCredentials(target Stream, credentials Credentials, resultsChan
resultsChan <- target
}
func attackCameraRoute(target Stream, routes Routes, resultsChan chan<- Stream, timeout time.Duration, log bool) {
func attackCameraRoute(c Curler, target Stream, routes Routes, resultsChan chan<- Stream, timeout time.Duration, log bool) {
for _, route := range routes {
ok := routeAttack(target, route, timeout, log)
ok := routeAttack(c, target, route, timeout, log)
if ok {
target.RouteFound = true
target.Route = route
@@ -157,12 +147,7 @@ func attackCameraRoute(target Stream, routes Routes, resultsChan chan<- Stream,
// AttackCredentials attempts to guess the provided targets' credentials using the given
// dictionary or the default dictionary if none was provided by the user.
func AttackCredentials(targets []Stream, credentials Credentials, timeout time.Duration, log bool) ([]Stream, error) {
err := curl.GlobalInit(curl.GLOBAL_ALL)
if err != nil {
return targets, errors.Wrap(err, "could not initialize curl")
}
func AttackCredentials(c Curler, targets []Stream, credentials Credentials, timeout time.Duration, log bool) ([]Stream, error) {
attacks := make(chan Stream)
defer close(attacks)
@@ -170,10 +155,10 @@ func AttackCredentials(targets []Stream, credentials Credentials, timeout time.D
for _, target := range targets {
err := validate.Struct(target)
if err != nil {
return targets, errors.Wrap(err, "invalid streams")
return targets, errors.Wrap(err, "invalid targets")
}
go attackCameraCredentials(target, credentials, attacks, timeout, log)
go attackCameraCredentials(c, target, credentials, attacks, timeout, log)
}
attackResults := []Stream{}
@@ -197,12 +182,7 @@ func AttackCredentials(targets []Stream, credentials Credentials, timeout time.D
// AttackRoute attempts to guess the provided targets' streaming routes using the given
// dictionary or the default dictionary if none was provided by the user.
func AttackRoute(targets []Stream, routes Routes, timeout time.Duration, log bool) ([]Stream, error) {
err := curl.GlobalInit(curl.GLOBAL_ALL)
if err != nil {
return targets, errors.Wrap(err, "could not initialize curl")
}
func AttackRoute(c Curler, targets []Stream, routes Routes, timeout time.Duration, log bool) ([]Stream, error) {
attacks := make(chan Stream)
defer close(attacks)
@@ -210,10 +190,10 @@ func AttackRoute(targets []Stream, routes Routes, timeout time.Duration, log boo
for _, target := range targets {
err := validate.Struct(target)
if err != nil {
return targets, errors.Wrap(err, "invalid streams")
return targets, errors.Wrap(err, "invalid targets")
}
go attackCameraRoute(target, routes, attacks, timeout, log)
go attackCameraRoute(c, target, routes, attacks, timeout, log)
}
attackResults := []Stream{}
+208 -25
View File
@@ -1,16 +1,35 @@
package cmrdr
import (
"errors"
"fmt"
"os"
"testing"
"time"
curl "github.com/andelf/go-curl"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// Again, since these tests use the curl library, I don't want to spend ages trying to mock
// the lib right now.
type CurlerMock struct {
mock.Mock
}
func (m *CurlerMock) Setopt(opt int, param interface{}) error {
args := m.Called(opt, param)
return args.Error(0)
}
func (m *CurlerMock) Perform() error {
args := m.Called()
return args.Error(0)
}
func (m *CurlerMock) Getinfo(info curl.CurlInfo) (interface{}, error) {
args := m.Called(info)
return args.Int(0), args.Error(1)
}
func TestAttackCredentials(t *testing.T) {
validStream1 := Stream{
@@ -25,58 +44,135 @@ func TestAttackCredentials(t *testing.T) {
Port: 1337,
}
invalidStream := Stream{
Device: "InvalidDevice",
}
fakeTargets := []Stream{validStream1, validStream2}
invalidTargets := []Stream{invalidStream}
fakeCredentials := Credentials{
Usernames: []string{"admin", "root"},
Passwords: []string{"12345", "root"},
}
vectors := []struct {
testCases := []struct {
targets []Stream
credentials Credentials
timeout time.Duration
log bool
status int
performErr error
getInfoErr error
invalidTargets bool
expectedStreams []Stream
expectedErrMsg string
}{
// Valid baseline
// Credentials found
{
targets: fakeTargets,
credentials: fakeCredentials,
timeout: 1 * time.Millisecond,
status: 404,
expectedStreams: fakeTargets,
},
// Camera accessed
{
targets: fakeTargets,
credentials: fakeCredentials,
timeout: 1 * time.Millisecond,
status: 200,
expectedStreams: fakeTargets,
},
// Invalid targets
{
targets: invalidTargets,
credentials: fakeCredentials,
timeout: 1 * time.Millisecond,
invalidTargets: true,
expectedErrMsg: "invalid targets",
expectedStreams: invalidTargets,
},
// curl perform fails
{
targets: fakeTargets,
credentials: fakeCredentials,
timeout: 1 * time.Millisecond,
performErr: errors.New("dummy error"),
expectedStreams: fakeTargets,
expectedErrMsg: "no credentials found",
},
// curl getinfo fails
{
targets: fakeTargets,
credentials: fakeCredentials,
timeout: 1 * time.Millisecond,
getInfoErr: errors.New("dummy error"),
expectedStreams: fakeTargets,
expectedErrMsg: "no credentials found",
},
// Credentials not found
{
targets: fakeTargets,
credentials: fakeCredentials,
timeout: 1 * time.Millisecond,
log: true,
status: 403,
expectedStreams: fakeTargets,
expectedErrMsg: "no credentials found",
},
// Valid baseline without logs
// Logging disabled
{
targets: fakeTargets,
credentials: fakeCredentials,
timeout: 1 * time.Millisecond,
log: false,
status: 403,
expectedStreams: fakeTargets,
expectedErrMsg: "no credentials found",
},
// TODO: Refacto and make tests with all possible error cases
}
for i, vector := range vectors {
results, err := AttackCredentials(vector.targets, vector.credentials, vector.timeout, vector.log)
for i, test := range testCases {
curlerMock := &CurlerMock{}
if len(vector.expectedErrMsg) > 0 {
if !test.invalidTargets {
curlerMock.On("Setopt", mock.Anything, mock.Anything).Return(nil)
curlerMock.On("Perform").Return(test.performErr)
if test.performErr == nil {
curlerMock.On("Getinfo", mock.Anything).Return(test.status, test.getInfoErr)
}
}
results, err := AttackCredentials(curlerMock, test.targets, test.credentials, test.timeout, test.log)
if len(test.expectedErrMsg) > 0 {
if err == nil {
fmt.Printf("unexpected success in AttackCredentials test, iteration %d. expected error: %s\n", i, vector.expectedErrMsg)
fmt.Printf("unexpected success in AttackCredentials test, iteration %d. expected error: %s\n", i, test.expectedErrMsg)
os.Exit(1)
}
assert.Contains(t, err.Error(), vector.expectedErrMsg, "wrong error message")
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
} else {
if err != nil {
fmt.Printf("unexpected error in AttackCredentials test, iteration %d: %v\n", i, err)
os.Exit(1)
}
for _, stream := range vector.expectedStreams {
for _, stream := range test.expectedStreams {
foundStream := false
for _, result := range results {
if result.Address == stream.Address && result.Device == stream.Device && result.Port == stream.Port {
@@ -86,8 +182,8 @@ func TestAttackCredentials(t *testing.T) {
assert.Equal(t, true, foundStream, "wrong streams parsed")
}
}
assert.Equal(t, len(vector.expectedStreams), len(results), "wrong streams parsed")
assert.Equal(t, len(test.expectedStreams), len(results), "wrong streams parsed")
curlerMock.AssertExpectations(t)
}
}
@@ -104,19 +200,92 @@ func TestAttackRoute(t *testing.T) {
Port: 1337,
}
invalidStream := Stream{
Device: "InvalidDevice",
}
fakeTargets := []Stream{validStream1, validStream2}
fakeRoutes := Routes{"live.sdp", "media.amp"}
invalidTargets := []Stream{invalidStream}
vectors := []struct {
testCases := []struct {
targets []Stream
routes Routes
timeout time.Duration
log bool
status int
performErr error
getInfoErr error
invalidTargets bool
expectedStreams []Stream
expectedErrMsg string
}{
// Valid baseline
// Route found
{
targets: fakeTargets,
routes: fakeRoutes,
timeout: 1 * time.Millisecond,
status: 403,
expectedStreams: fakeTargets,
},
// Route found
{
targets: fakeTargets,
routes: fakeRoutes,
timeout: 1 * time.Millisecond,
status: 401,
expectedStreams: fakeTargets,
},
// Camera accessed
{
targets: fakeTargets,
routes: fakeRoutes,
timeout: 1 * time.Millisecond,
status: 200,
expectedStreams: fakeTargets,
},
// Invalid targets
{
targets: invalidTargets,
routes: fakeRoutes,
timeout: 1 * time.Millisecond,
invalidTargets: true,
expectedErrMsg: "invalid targets",
expectedStreams: invalidTargets,
},
// curl perform fails
{
targets: fakeTargets,
routes: fakeRoutes,
timeout: 1 * time.Millisecond,
performErr: errors.New("dummy error"),
expectedStreams: fakeTargets,
expectedErrMsg: "no routes found",
},
// curl getinfo fails
{
targets: fakeTargets,
routes: fakeRoutes,
timeout: 1 * time.Millisecond,
getInfoErr: errors.New("dummy error"),
expectedStreams: fakeTargets,
expectedErrMsg: "no routes found",
},
// Routes not found
{
targets: fakeTargets,
routes: fakeRoutes,
@@ -126,7 +295,7 @@ func TestAttackRoute(t *testing.T) {
expectedStreams: fakeTargets,
expectedErrMsg: "no routes found",
},
// Valid baseline without logs
// Logs disabled
{
targets: fakeTargets,
routes: fakeRoutes,
@@ -136,23 +305,32 @@ func TestAttackRoute(t *testing.T) {
expectedStreams: fakeTargets,
expectedErrMsg: "no routes found",
},
// TODO: Refacto and make tests with all possible error cases
}
for i, vector := range vectors {
results, err := AttackRoute(vector.targets, vector.routes, vector.timeout, vector.log)
for i, test := range testCases {
curlerMock := &CurlerMock{}
if len(vector.expectedErrMsg) > 0 {
if !test.invalidTargets {
curlerMock.On("Setopt", mock.Anything, mock.Anything).Return(nil)
curlerMock.On("Perform").Return(test.performErr)
if test.performErr == nil {
curlerMock.On("Getinfo", mock.Anything).Return(test.status, test.getInfoErr)
}
}
results, err := AttackRoute(curlerMock, test.targets, test.routes, test.timeout, test.log)
if len(test.expectedErrMsg) > 0 {
if err == nil {
fmt.Printf("unexpected success in AttackRoute test, iteration %d. expected error: %s\n", i, vector.expectedErrMsg)
fmt.Printf("unexpected success in AttackRoute test, iteration %d. expected error: %s\n", i, test.expectedErrMsg)
os.Exit(1)
}
assert.Contains(t, err.Error(), vector.expectedErrMsg, "wrong error message")
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
} else {
if err != nil {
fmt.Printf("unexpected error in AttackRoute test, iteration %d: %v\n", i, err)
os.Exit(1)
}
for _, stream := range vector.expectedStreams {
for _, stream := range test.expectedStreams {
foundStream := false
for _, result := range results {
if result.Address == stream.Address && result.Device == stream.Device && result.Port == stream.Port {
@@ -162,6 +340,11 @@ func TestAttackRoute(t *testing.T) {
assert.Equal(t, true, foundStream, "wrong streams parsed")
}
}
assert.Equal(t, len(vector.expectedStreams), len(results), "wrong streams parsed")
assert.Equal(t, len(test.expectedStreams), len(results), "wrong streams parsed")
curlerMock.AssertExpectations(t)
}
}
func TestDotWrite(t *testing.T) {
assert.Equal(t, true, doNotWrite(nil, nil))
}
+13 -6
View File
@@ -8,12 +8,13 @@ import (
"time"
"github.com/EtixLabs/cameradar"
curl "github.com/andelf/go-curl"
"github.com/fatih/color"
"github.com/gernest/wow"
"github.com/gernest/wow/spin"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/fatih/color"
)
type options struct {
@@ -92,6 +93,13 @@ func main() {
w := startSpinner(options.EnableLogs)
err = curl.GlobalInit(curl.GLOBAL_ALL)
c := curl.EasyInit()
if err != nil || c == nil {
printErr(errors.New("libcurl initialization failed"))
}
defer curl.GlobalCleanup()
updateSpinner(w, "Loading dictionaries...", options.EnableLogs)
gopath := os.Getenv("GOPATH")
options.Credentials = strings.Replace(options.Credentials, "<GOPATH>", gopath, 1)
@@ -116,15 +124,14 @@ func main() {
}
// Most cameras will be accessed successfully with these two attacks
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Attacking their routes...", options.EnableLogs)
streams, err = cmrdr.AttackRoute(streams, routes, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
streams, err = cmrdr.AttackRoute(c, streams, routes, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
if err != nil && len(streams) > 0 {
printErr(err)
}
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Attacking their credentials...", options.EnableLogs)
streams, err = cmrdr.AttackCredentials(streams, credentials, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
streams, err = cmrdr.AttackCredentials(c, streams, credentials, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
if err != nil && len(streams) > 0 {
printErr(err)
}
@@ -135,7 +142,7 @@ func main() {
if stream.RouteFound == false || stream.CredentialsFound == false {
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Final attack...", options.EnableLogs)
streams, err = cmrdr.AttackRoute(streams, routes, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
streams, err = cmrdr.AttackRoute(c, streams, routes, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
if err != nil && len(streams) > 0 {
printErr(err)
}
BIN
View File
Binary file not shown.
+13
View File
@@ -0,0 +1,13 @@
package cmrdr
import (
curl "github.com/andelf/go-curl"
)
// Curler is an interface that implements the CURL interface of the go-curl library
// Used for mocking
type Curler interface {
Setopt(opt int, param interface{}) error
Perform() error
Getinfo(info curl.CurlInfo) (interface{}, error)
}
+31 -31
View File
@@ -37,7 +37,7 @@ func TestNmapRun(t *testing.T) {
execCommand = fakeExecCommand
defer func() { execCommand = exec.Command }()
vectors := []struct {
testCases := []struct {
targets string
ports string
resultFilePath string
@@ -65,14 +65,14 @@ func TestNmapRun(t *testing.T) {
expectedErrMsg: "invalid nmap speed value",
},
}
for _, vector := range vectors {
err := NmapRun(vector.targets, vector.ports, vector.resultFilePath, vector.nmapSpeed, vector.enableLogs)
if len(vector.expectedErrMsg) > 0 {
for _, test := range testCases {
err := NmapRun(test.targets, test.ports, test.resultFilePath, test.nmapSpeed, test.enableLogs)
if len(test.expectedErrMsg) > 0 {
if err == nil {
fmt.Printf("unexpected success. expected error: %s\n", vector.expectedErrMsg)
fmt.Printf("unexpected success. expected error: %s\n", test.expectedErrMsg)
os.Exit(1)
}
assert.Contains(t, err.Error(), vector.expectedErrMsg, "wrong error message")
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
} else {
if err != nil {
fmt.Printf("unexpected error: %v\n", err)
@@ -107,7 +107,7 @@ func TestNmapParseResults(t *testing.T) {
Port: 1337,
}
vectors := []struct {
testCases := []struct {
fileExists bool
streamsXML *nmapResult
@@ -165,7 +165,7 @@ func TestNmapParseResults(t *testing.T) {
fileExists: true,
},
// File exists
// Two invalid streams, no error
// Two invalid targets, no error
{
fileExists: true,
expectedStreams: []Stream{invalidStreamNoPort, invalidStreamNoAddress},
@@ -261,11 +261,11 @@ func TestNmapParseResults(t *testing.T) {
expectedErrMsg: "expected element type <nmaprun> but have <failure>",
},
}
for i, vector := range vectors {
for i, test := range testCases {
filePath := "/tmp/cameradar_test_parse_results_" + fmt.Sprint(i) + ".xml"
// create file
if vector.fileExists {
if test.fileExists {
_, err := os.Create(filePath)
if err != nil {
fmt.Printf("could not create xml file for NmapParseResults: %v. iteration: %d. file path: %s\n", err, i, filePath)
@@ -273,10 +273,10 @@ func TestNmapParseResults(t *testing.T) {
}
// marshal and write
if vector.streamsXML != nil {
streams, err := xml.Marshal(vector.streamsXML)
if test.streamsXML != nil {
streams, err := xml.Marshal(test.streamsXML)
if err != nil {
fmt.Printf("invalid streams for NmapParseResults: %v. iteration: %d. streams: %v\n", err, i, vector.streamsXML)
fmt.Printf("invalid targets for NmapParseResults: %v. iteration: %d. streams: %v\n", err, i, test.streamsXML)
os.Exit(1)
}
@@ -295,18 +295,18 @@ func TestNmapParseResults(t *testing.T) {
}
results, err := NmapParseResults(filePath)
if len(vector.expectedErrMsg) > 0 {
if len(test.expectedErrMsg) > 0 {
if err == nil {
fmt.Printf("unexpected success. expected error: %s\n", vector.expectedErrMsg)
fmt.Printf("unexpected success. expected error: %s\n", test.expectedErrMsg)
os.Exit(1)
}
assert.Contains(t, err.Error(), vector.expectedErrMsg, "wrong error message")
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
} else {
if err != nil {
fmt.Printf("unexpected error: %v\n", err)
os.Exit(1)
}
for _, stream := range vector.expectedStreams {
for _, stream := range test.expectedStreams {
foundStream := false
for _, result := range results {
if result.Address == stream.Address && result.Device == stream.Device && result.Port == stream.Port {
@@ -316,7 +316,7 @@ func TestNmapParseResults(t *testing.T) {
assert.Equal(t, true, foundStream, "wrong streams parsed")
}
}
assert.Equal(t, len(vector.expectedStreams), len(results), "wrong streams parsed")
assert.Equal(t, len(test.expectedStreams), len(results), "wrong streams parsed")
}
}
@@ -348,7 +348,7 @@ func TestDiscover(t *testing.T) {
Port: 1337,
}
vectors := []struct {
testCases := []struct {
targets string
ports string
resultFilePath string
@@ -526,7 +526,7 @@ func TestDiscover(t *testing.T) {
enableLogs: false,
},
// File exists
// Two invalid streams, no error
// Two invalid targets, no error
{
fileExists: true,
expectedStreams: []Stream{invalidStreamNoPort, invalidStreamNoAddress},
@@ -642,11 +642,11 @@ func TestDiscover(t *testing.T) {
enableLogs: false,
},
}
for i, vector := range vectors {
for i, test := range testCases {
filePath := "/tmp/cameradar_test_discover_" + fmt.Sprint(i) + ".xml"
// create file
if vector.fileExists {
if test.fileExists {
_, err := os.Create(filePath)
if err != nil {
fmt.Printf("could not create xml file for Discover: %v. iteration: %d. file path: %s\n", err, i, filePath)
@@ -654,10 +654,10 @@ func TestDiscover(t *testing.T) {
}
// marshal and write
if vector.streamsXML != nil {
streams, err := xml.Marshal(vector.streamsXML)
if test.streamsXML != nil {
streams, err := xml.Marshal(test.streamsXML)
if err != nil {
fmt.Printf("invalid streams for Discover: %v. iteration: %d. streams: %v\n", err, i, vector.streamsXML)
fmt.Printf("invalid targets for Discover: %v. iteration: %d. streams: %v\n", err, i, test.streamsXML)
os.Exit(1)
}
@@ -675,20 +675,20 @@ func TestDiscover(t *testing.T) {
}
}
results, err := Discover(vector.targets, vector.ports, filePath, vector.nmapSpeed, vector.enableLogs)
results, err := Discover(test.targets, test.ports, filePath, test.nmapSpeed, test.enableLogs)
if len(vector.expectedErrMsg) > 0 {
if len(test.expectedErrMsg) > 0 {
if err == nil {
fmt.Printf("unexpected success in Discover test, iteration %d. expected error: %s\n", i, vector.expectedErrMsg)
fmt.Printf("unexpected success in Discover test, iteration %d. expected error: %s\n", i, test.expectedErrMsg)
os.Exit(1)
}
assert.Contains(t, err.Error(), vector.expectedErrMsg, "wrong error message")
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
} else {
if err != nil {
fmt.Printf("unexpected error in Discover test, iteration %d: %v\n", i, err)
os.Exit(1)
}
for _, stream := range vector.expectedStreams {
for _, stream := range test.expectedStreams {
foundStream := false
for _, result := range results {
if result.Address == stream.Address && result.Device == stream.Device && result.Port == stream.Port {
@@ -698,6 +698,6 @@ func TestDiscover(t *testing.T) {
assert.Equal(t, true, foundStream, "wrong streams parsed")
}
}
assert.Equal(t, len(vector.expectedStreams), len(results), "wrong streams parsed")
assert.Equal(t, len(test.expectedStreams), len(results), "wrong streams parsed")
}
}
+12 -12
View File
@@ -31,7 +31,7 @@ func TestReplace(t *testing.T) {
Port: 1337,
}
vectors := []struct {
testCases := []struct {
streams []Stream
newStream Stream
@@ -45,10 +45,10 @@ func TestReplace(t *testing.T) {
expectedStreams: []Stream{validStream1, validStream2, invalidStreamNoPortModified},
},
}
for _, vector := range vectors {
streams := replace(vector.streams, vector.newStream)
for _, test := range testCases {
streams := replace(test.streams, test.newStream)
for _, stream := range vector.streams {
for _, stream := range test.streams {
foundStream := false
for _, result := range streams {
if result.Address == stream.Address && result.Device == stream.Device && result.Port == stream.Port {
@@ -69,7 +69,7 @@ func TestGetCameraRTSPURL(t *testing.T) {
Port: 1337,
}
vectors := []struct {
testCases := []struct {
stream Stream
expectedRTSPURL string
@@ -81,9 +81,9 @@ func TestGetCameraRTSPURL(t *testing.T) {
expectedRTSPURL: "rtsp://ullaakut:ba69897483886f0d2b0afb6345b76c0c@1.2.3.4:1337/cameradar.sdp",
},
}
for _, vector := range vectors {
output := GetCameraRTSPURL(vector.stream)
assert.Equal(t, vector.expectedRTSPURL, output, "wrong RTSP URL generated")
for _, test := range testCases {
output := GetCameraRTSPURL(test.stream)
assert.Equal(t, test.expectedRTSPURL, output, "wrong RTSP URL generated")
}
}
@@ -92,7 +92,7 @@ func TestGetCameraAdminPanelURL(t *testing.T) {
Address: "1.2.3.4",
}
vectors := []struct {
testCases := []struct {
stream Stream
expectedRTSPURL string
@@ -104,8 +104,8 @@ func TestGetCameraAdminPanelURL(t *testing.T) {
expectedRTSPURL: "http://1.2.3.4/",
},
}
for _, vector := range vectors {
output := GetCameraAdminPanelURL(vector.stream)
assert.Equal(t, vector.expectedRTSPURL, output, "wrong Admin Panel URL generated")
for _, test := range testCases {
output := GetCameraAdminPanelURL(test.stream)
assert.Equal(t, test.expectedRTSPURL, output, "wrong Admin Panel URL generated")
}
}
+109 -17
View File
@@ -16,7 +16,7 @@ func TestLoadCredentials(t *testing.T) {
Passwords: []string{"12345", "root"},
}
vectors := []struct {
testCases := []struct {
input []byte
fileExists bool
@@ -47,17 +47,17 @@ func TestLoadCredentials(t *testing.T) {
input: []byte("{\"invalid\":\"json\"}"),
},
}
for i, vector := range vectors {
for i, test := range testCases {
filePath := "/tmp/cameradar_test_load_credentials_" + fmt.Sprint(i) + ".xml"
// create file
if vector.fileExists {
if test.fileExists {
_, err := os.Create(filePath)
if err != nil {
fmt.Printf("could not create xml file for LoadCredentials: %v. iteration: %d. file path: %s\n", err, i, filePath)
os.Exit(1)
}
err = ioutil.WriteFile(filePath, vector.input, 0644)
err = ioutil.WriteFile(filePath, test.input, 0644)
if err != nil {
fmt.Printf("could not write xml file for LoadCredentials: %v. iteration: %d. file path: %s\n", err, i, filePath)
os.Exit(1)
@@ -65,18 +65,18 @@ func TestLoadCredentials(t *testing.T) {
}
result, err := LoadCredentials(filePath)
if len(vector.expectedErrMsg) > 0 {
if len(test.expectedErrMsg) > 0 {
if err == nil {
fmt.Printf("unexpected success in LoadCredentials test, iteration %d. expected error: %s\n", i, vector.expectedErrMsg)
fmt.Printf("unexpected success in LoadCredentials test, iteration %d. expected error: %s\n", i, test.expectedErrMsg)
os.Exit(1)
}
assert.Contains(t, err.Error(), vector.expectedErrMsg, "wrong error message")
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
} else {
if err != nil {
fmt.Printf("unexpected error in LoadCredentials test, iteration %d: %v\n", i, err)
os.Exit(1)
}
for _, expectedUsername := range vector.expectedOutput.Usernames {
for _, expectedUsername := range test.expectedOutput.Usernames {
foundUsername := false
for _, username := range result.Usernames {
if username == expectedUsername {
@@ -85,7 +85,7 @@ func TestLoadCredentials(t *testing.T) {
}
assert.Equal(t, true, foundUsername, "wrong usernames parsed")
}
for _, expectedPassword := range vector.expectedOutput.Passwords {
for _, expectedPassword := range test.expectedOutput.Passwords {
foundPassword := false
for _, password := range result.Passwords {
if password == expectedPassword {
@@ -102,7 +102,7 @@ func TestLoadRoutes(t *testing.T) {
routesJSONString := []byte("admin\nroot")
validRoutes := Routes{"admin", "root"}
vectors := []struct {
testCases := []struct {
input []byte
fileExists bool
@@ -127,17 +127,17 @@ func TestLoadRoutes(t *testing.T) {
input: []byte(""),
},
}
for i, vector := range vectors {
for i, test := range testCases {
filePath := "/tmp/cameradar_test_load_routes_" + fmt.Sprint(i) + ".xml"
// create file
if vector.fileExists {
if test.fileExists {
_, err := os.Create(filePath)
if err != nil {
fmt.Printf("could not create xml file for LoadRoutes: %v. iteration: %d. file path: %s\n", err, i, filePath)
os.Exit(1)
}
err = ioutil.WriteFile(filePath, vector.input, 0644)
err = ioutil.WriteFile(filePath, test.input, 0644)
if err != nil {
fmt.Printf("could not write xml file for LoadRoutes: %v. iteration: %d. file path: %s\n", err, i, filePath)
os.Exit(1)
@@ -145,18 +145,18 @@ func TestLoadRoutes(t *testing.T) {
}
result, err := LoadRoutes(filePath)
if len(vector.expectedErrMsg) > 0 {
if len(test.expectedErrMsg) > 0 {
if err == nil {
fmt.Printf("unexpected success in LoadRoutes test, iteration %d. expected error: %s\n", i, vector.expectedErrMsg)
fmt.Printf("unexpected success in LoadRoutes test, iteration %d. expected error: %s\n", i, test.expectedErrMsg)
os.Exit(1)
}
assert.Contains(t, err.Error(), vector.expectedErrMsg, "wrong error message")
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
} else {
if err != nil {
fmt.Printf("unexpected error in LoadRoutes test, iteration %d: %v\n", i, err)
os.Exit(1)
}
for _, expectedRoute := range vector.expectedOutput {
for _, expectedRoute := range test.expectedOutput {
foundRoute := false
for _, route := range result {
if route == expectedRoute {
@@ -168,3 +168,95 @@ func TestLoadRoutes(t *testing.T) {
}
}
}
func TestParseCredentialsFromString(t *testing.T) {
defaultCredentials := Credentials{
Usernames: []string{
"",
"admin",
"Admin",
"Administrator",
"root",
"supervisor",
"ubnt",
"service",
"Dinion",
"administrator",
"admin1",
},
Passwords: []string{
"",
"admin",
"9999",
"123456",
"pass",
"camera",
"1234",
"12345",
"fliradmin",
"system",
"jvc",
"meinsm",
"root",
"4321",
"111111",
"1111111",
"password",
"ikwd",
"supervisor",
"ubnt",
"wbox123",
"service",
},
}
testCases := []struct {
str string
expectedResult Credentials
}{
{
str: "{\"usernames\":[\"\",\"admin\",\"Admin\",\"Administrator\",\"root\",\"supervisor\",\"ubnt\",\"service\",\"Dinion\",\"administrator\",\"admin1\"],\"passwords\":[\"\",\"admin\",\"9999\",\"123456\",\"pass\",\"camera\",\"1234\",\"12345\",\"fliradmin\",\"system\",\"jvc\",\"meinsm\",\"root\",\"4321\",\"111111\",\"1111111\",\"password\",\"ikwd\",\"supervisor\",\"ubnt\",\"wbox123\",\"service\"]}",
expectedResult: defaultCredentials,
},
{
str: "{}",
expectedResult: Credentials{},
},
{
str: "{\"invalid_field\":42}",
expectedResult: Credentials{},
},
{
str: "not json",
expectedResult: Credentials{},
},
}
for _, test := range testCases {
parsedCredentials, _ := ParseCredentialsFromString(test.str)
assert.Equal(t, test.expectedResult, parsedCredentials, "unexpected result, parse error")
}
}
func TestParseRoutesFromString(t *testing.T) {
testCases := []struct {
str string
expectedResult Routes
}{
{
str: "a\nb\nc",
expectedResult: []string{"a", "b", "c"},
},
{
str: "a",
expectedResult: []string{"a"},
},
{
str: "",
expectedResult: []string{""},
},
}
for _, test := range testCases {
parsedRoutes := ParseRoutesFromString(test.str)
assert.Equal(t, test.expectedResult, parsedRoutes, "unexpected result, parse error")
}
}