Passed
Pull Request — master (#59)
by Stefano
02:11
created

pkg/cmd/scan_integration_test.go   B

Size/Duplication

Total Lines 562
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 44
eloc 383
dl 0
loc 562
rs 8.8798
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A cmd_test.TestScanWithRemoteDictionary 0 38 3
A cmd_test.TestShouldFailToScanWithAnUnreachableSocks5Server 0 35 2
A cmd_test.TestWhenProvidingCookiesInWrongFormatShouldErr 0 30 2
B cmd_test.TestScanWithCookieJar 0 52 5
A cmd_test.TestScanCommandCanBeInterrupted 0 40 4
A cmd_test.TestScanCommand 0 52 4
A cmd_test.TestScanWithUserAgentFlag 0 36 3
A cmd_test.TestScanWithCookies 0 40 3
A cmd_test.TestScanWithNoTargetShouldErr 0 18 2
A cmd_test.TestScanWithMalformedHeaderShouldErr 0 30 2
A cmd_test.TestStartScanWithSocks5ShouldFindResultsWhenAServerIsAvailable 0 32 2
A cmd_test.TestScanWithUnknownFlagShouldErr 0 24 2
A cmd_test.TestScanWithHeaders 0 38 3
A cmd_test.TestShouldFailToStartWithAnInvalidSocks5Address 0 30 2
A cmd_test.startSocks5TestServer 0 20 5
1
package cmd_test
2
3
import (
4
	"net"
5
	"net/http"
6
	"net/http/httptest"
7
	"sync"
8
	"syscall"
9
	"testing"
10
	"time"
11
12
	"github.com/armon/go-socks5"
13
	"github.com/stefanoj3/dirstalk/pkg/common/test"
14
	"github.com/stretchr/testify/assert"
15
)
16
17
const socks5TestServerHost = "127.0.0.1:8899"
18
19
func TestScanCommand(t *testing.T) {
20
	logger, _ := test.NewLogger()
21
22
	c, err := createCommand(logger)
23
	assert.NoError(t, err)
24
	assert.NotNil(t, c)
25
26
	testServer, serverAssertion := test.NewServerWithAssertion(
27
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
28
			if r.URL.Path == "/test/" {
29
				w.WriteHeader(http.StatusOK)
30
				return
31
			}
32
33
			w.WriteHeader(http.StatusNotFound)
34
		}),
35
	)
36
	defer testServer.Close()
37
38
	_, _, err = executeCommand(
39
		c,
40
		"scan",
41
		testServer.URL,
42
		"--dictionary",
43
		"testdata/dict2.txt",
44
		"-v",
45
		"--http-timeout",
46
		"300",
47
	)
48
	assert.NoError(t, err)
49
50
	assert.Equal(t, 8, serverAssertion.Len())
51
52
	requestsMap := map[string]string{}
53
54
	serverAssertion.Range(func(_ int, r http.Request) {
55
		requestsMap[r.URL.Path] = r.Method
56
	})
57
58
	expectedRequests := map[string]string{
59
		"/test/":               http.MethodGet,
60
		"/test/home":           http.MethodGet,
61
		"/test/blabla":         http.MethodGet,
62
		"/test/home/index.php": http.MethodGet,
63
		"/test/test/":          http.MethodGet,
64
65
		"/home":           http.MethodGet,
66
		"/blabla":         http.MethodGet,
67
		"/home/index.php": http.MethodGet,
68
	}
69
70
	assert.Equal(t, expectedRequests, requestsMap)
71
}
72
73
func TestScanWithNoTargetShouldErr(t *testing.T) {
74
	logger, _ := test.NewLogger()
75
76
	c, err := createCommand(logger)
77
	assert.NoError(t, err)
78
	assert.NotNil(t, c)
79
80
	testServer, serverAssertion := test.NewServerWithAssertion(
81
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
82
			w.WriteHeader(http.StatusNotFound)
83
		}),
84
	)
85
	defer testServer.Close()
86
87
	_, _, err = executeCommand(c, "scan", "--dictionary", "testdata/dict2.txt")
88
	assert.Error(t, err)
89
90
	assert.Equal(t, 0, serverAssertion.Len())
91
}
92
93
func TestScanCommandCanBeInterrupted(t *testing.T) {
94
	logger, loggerBuffer := test.NewLogger()
95
96
	c, err := createCommand(logger)
97
	assert.NoError(t, err)
98
	assert.NotNil(t, c)
99
100
	testServer, serverAssertion := test.NewServerWithAssertion(
101
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
102
			time.Sleep(time.Millisecond * 650)
103
104
			if r.URL.Path == "/test/" {
105
				w.WriteHeader(http.StatusOK)
106
				return
107
			}
108
109
			w.WriteHeader(http.StatusNotFound)
110
		}),
111
	)
112
	defer testServer.Close()
113
114
	go func() {
115
		time.Sleep(time.Millisecond * 200)
116
		_ = syscall.Kill(syscall.Getpid(), syscall.SIGINT)
117
	}()
118
119
	_, _, err = executeCommand(
120
		c,
121
		"scan",
122
		testServer.URL,
123
		"--dictionary",
124
		"testdata/dict2.txt",
125
		"-v",
126
		"--http-timeout",
127
		"900",
128
	)
129
	assert.NoError(t, err)
130
131
	assert.True(t, serverAssertion.Len() > 0)
132
	assert.Contains(t, loggerBuffer.String(), "Received sigint")
133
}
134
135
func TestScanWithRemoteDictionary(t *testing.T) {
136
	logger, _ := test.NewLogger()
137
138
	c, err := createCommand(logger)
139
	assert.NoError(t, err)
140
	assert.NotNil(t, c)
141
142
	dictionaryServer := httptest.NewServer(
143
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
144
			dict := `home
145
home/index.php
146
blabla
147
`
148
			w.WriteHeader(http.StatusOK)
149
			_, _ = w.Write([]byte(dict))
150
		}),
151
	)
152
	defer dictionaryServer.Close()
153
154
	testServer, serverAssertion := test.NewServerWithAssertion(
155
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
156
			w.WriteHeader(http.StatusNotFound)
157
		}),
158
	)
159
	defer testServer.Close()
160
161
	_, _, err = executeCommand(
162
		c,
163
		"scan",
164
		testServer.URL,
165
		"--dictionary",
166
		dictionaryServer.URL,
167
		"--http-timeout",
168
		"300",
169
	)
170
	assert.NoError(t, err)
171
172
	assert.Equal(t, 3, serverAssertion.Len())
173
}
174
175
func TestScanWithUserAgentFlag(t *testing.T) {
176
	const testUserAgent = "my_test_user_agent"
177
178
	logger, loggerBuffer := test.NewLogger()
179
180
	c, err := createCommand(logger)
181
	assert.NoError(t, err)
182
	assert.NotNil(t, c)
183
184
	testServer, serverAssertion := test.NewServerWithAssertion(
185
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
186
			w.WriteHeader(http.StatusNotFound)
187
		}),
188
	)
189
	defer testServer.Close()
190
191
	_, _, err = executeCommand(
192
		c,
193
		"scan",
194
		testServer.URL,
195
		"--user-agent",
196
		testUserAgent,
197
		"--dictionary",
198
		"testdata/dict.txt",
199
		"--http-timeout",
200
		"300",
201
	)
202
	assert.NoError(t, err)
203
204
	assert.Equal(t, 3, serverAssertion.Len())
205
	serverAssertion.Range(func(_ int, r http.Request) {
206
		assert.Equal(t, testUserAgent, r.Header.Get("User-Agent"))
207
	})
208
209
	// to ensure we print the user agent to the cli
210
	assert.Contains(t, loggerBuffer.String(), testUserAgent)
211
}
212
213
func TestScanWithCookies(t *testing.T) {
214
	logger, loggerBuffer := test.NewLogger()
215
216
	c, err := createCommand(logger)
217
	assert.NoError(t, err)
218
	assert.NotNil(t, c)
219
220
	testServer, serverAssertion := test.NewServerWithAssertion(
221
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
222
	)
223
	defer testServer.Close()
224
225
	_, _, err = executeCommand(
226
		c,
227
		"scan",
228
		testServer.URL,
229
		"--cookie",
230
		"name1=val1",
231
		"--cookie",
232
		"name2=val2",
233
		"--dictionary",
234
		"testdata/dict.txt",
235
		"--http-timeout",
236
		"300",
237
	)
238
	assert.NoError(t, err)
239
240
	serverAssertion.Range(func(_ int, r http.Request) {
241
		assert.Equal(t, 2, len(r.Cookies()))
242
243
		assert.Equal(t, r.Cookies()[0].Name, "name1")
244
		assert.Equal(t, r.Cookies()[0].Value, "val1")
245
246
		assert.Equal(t, r.Cookies()[1].Name, "name2")
247
		assert.Equal(t, r.Cookies()[1].Value, "val2")
248
	})
249
250
	// to ensure we print the cookies to the cli
251
	assert.Contains(t, loggerBuffer.String(), "name1=val1")
252
	assert.Contains(t, loggerBuffer.String(), "name2=val2")
253
}
254
255
func TestWhenProvidingCookiesInWrongFormatShouldErr(t *testing.T) {
256
	const malformedCookie = "gibberish"
257
258
	logger, _ := test.NewLogger()
259
260
	c, err := createCommand(logger)
261
	assert.NoError(t, err)
262
	assert.NotNil(t, c)
263
264
	testServer, serverAssertion := test.NewServerWithAssertion(
265
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
266
			w.WriteHeader(http.StatusNotFound)
267
		}),
268
	)
269
	defer testServer.Close()
270
271
	_, _, err = executeCommand(
272
		c,
273
		"scan",
274
		testServer.URL,
275
		"--cookie",
276
		malformedCookie,
277
		"--dictionary",
278
		"testdata/dict.txt",
279
	)
280
	assert.Error(t, err)
281
	assert.Contains(t, err.Error(), "cookie format is invalid")
282
	assert.Contains(t, err.Error(), malformedCookie)
283
284
	assert.Equal(t, 0, serverAssertion.Len())
285
}
286
287
func TestScanWithCookieJar(t *testing.T) {
288
	const (
289
		serverCookieName  = "server_cookie_name"
290
		serverCookieValue = "server_cookie_value"
291
	)
292
293
	logger, _ := test.NewLogger()
294
295
	c, err := createCommand(logger)
296
	assert.NoError(t, err)
297
	assert.NotNil(t, c)
298
299
	once := sync.Once{}
300
	testServer, serverAssertion := test.NewServerWithAssertion(
301
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
302
			once.Do(func() {
303
				http.SetCookie(
304
					w,
305
					&http.Cookie{
306
						Name:    serverCookieName,
307
						Value:   serverCookieValue,
308
						Expires: time.Now().AddDate(0, 1, 0),
309
					},
310
				)
311
			})
312
		}),
313
	)
314
	defer testServer.Close()
315
316
	_, _, err = executeCommand(
317
		c,
318
		"scan",
319
		testServer.URL,
320
		"--use-cookie-jar",
321
		"--dictionary",
322
		"testdata/dict.txt",
323
		"--http-timeout",
324
		"300",
325
		"-t",
326
		"1",
327
	)
328
	assert.NoError(t, err)
329
330
	serverAssertion.Range(func(index int, r http.Request) {
331
		if index == 0 { // first request should have no cookies
332
			assert.Equal(t, 0, len(r.Cookies()))
333
			return
334
		}
335
336
		assert.Equal(t, 1, len(r.Cookies()))
337
		assert.Equal(t, r.Cookies()[0].Name, serverCookieName)
338
		assert.Equal(t, r.Cookies()[0].Value, serverCookieValue)
339
	})
340
}
341
342
func TestScanWithUnknownFlagShouldErr(t *testing.T) {
343
	logger, _ := test.NewLogger()
344
345
	c, err := createCommand(logger)
346
	assert.NoError(t, err)
347
	assert.NotNil(t, c)
348
349
	testServer, serverAssertion := test.NewServerWithAssertion(
350
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
351
	)
352
	defer testServer.Close()
353
354
	_, _, err = executeCommand(
355
		c,
356
		"scan",
357
		testServer.URL,
358
		"--gibberishflag",
359
		"--dictionary",
360
		"testdata/dict.txt",
361
	)
362
	assert.Error(t, err)
363
	assert.Contains(t, err.Error(), "unknown flag")
364
365
	assert.Equal(t, 0, serverAssertion.Len())
366
}
367
368
func TestScanWithHeaders(t *testing.T) {
369
	logger, loggerBuffer := test.NewLogger()
370
371
	c, err := createCommand(logger)
372
	assert.NoError(t, err)
373
	assert.NotNil(t, c)
374
375
	testServer, serverAssertion := test.NewServerWithAssertion(
376
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
377
	)
378
	defer testServer.Close()
379
380
	_, _, err = executeCommand(
381
		c,
382
		"scan",
383
		testServer.URL,
384
		"--header",
385
		"Accept-Language: en-US,en;q=0.5",
386
		"--header",
387
		`"Authorization: Bearer 123"`,
388
		"--dictionary",
389
		"testdata/dict.txt",
390
		"--http-timeout",
391
		"300",
392
	)
393
	assert.NoError(t, err)
394
395
	serverAssertion.Range(func(_ int, r http.Request) {
396
		assert.Equal(t, 2, len(r.Header))
397
398
		assert.Equal(t, "en-US,en;q=0.5", r.Header.Get("Accept-Language"))
399
		assert.Equal(t, "Bearer 123", r.Header.Get("Authorization"))
400
	})
401
402
	// to ensure we print the headers to the cli
403
	assert.Contains(t, loggerBuffer.String(), "Accept-Language")
404
	assert.Contains(t, loggerBuffer.String(), "Authorization")
405
	assert.Contains(t, loggerBuffer.String(), "Bearer 123")
406
}
407
408
func TestScanWithMalformedHeaderShouldErr(t *testing.T) {
409
	const malformedHeader = "gibberish"
410
411
	logger, _ := test.NewLogger()
412
413
	c, err := createCommand(logger)
414
	assert.NoError(t, err)
415
	assert.NotNil(t, c)
416
417
	testServer, serverAssertion := test.NewServerWithAssertion(
418
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
419
	)
420
	defer testServer.Close()
421
422
	_, _, err = executeCommand(
423
		c,
424
		"scan",
425
		testServer.URL,
426
		"--header",
427
		"Accept-Language: en-US,en;q=0.5",
428
		"--header",
429
		malformedHeader,
430
		"--dictionary",
431
		"testdata/dict.txt",
432
	)
433
	assert.Error(t, err)
434
	assert.Contains(t, err.Error(), malformedHeader)
435
	assert.Contains(t, err.Error(), "header is in invalid format")
436
437
	assert.Equal(t, 0, serverAssertion.Len())
438
}
439
440
func TestStartScanWithSocks5ShouldFindResultsWhenAServerIsAvailable(t *testing.T) {
441
	logger, _ := test.NewLogger()
442
443
	c, err := createCommand(logger)
444
	assert.NoError(t, err)
445
	assert.NotNil(t, c)
446
447
	testServer, serverAssertion := test.NewServerWithAssertion(
448
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
449
			w.WriteHeader(http.StatusNotFound)
450
		}),
451
	)
452
	defer testServer.Close()
453
454
	socks5Server := startSocks5TestServer(t)
455
	defer socks5Server.Close()
456
457
	_, _, err = executeCommand(
458
		c,
459
		"scan",
460
		testServer.URL,
461
		"--dictionary",
462
		"testdata/dict.txt",
463
		"-v",
464
		"--http-timeout",
465
		"300",
466
		"--socks5",
467
		socks5TestServerHost,
468
	)
469
	assert.NoError(t, err)
470
471
	assert.Equal(t, 3, serverAssertion.Len())
472
}
473
474
func TestShouldFailToScanWithAnUnreachableSocks5Server(t *testing.T) {
475
	logger, loggerBuffer := test.NewLogger()
476
477
	c, err := createCommand(logger)
478
	assert.NoError(t, err)
479
	assert.NotNil(t, c)
480
481
	testServer, serverAssertion := test.NewServerWithAssertion(
482
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
483
			w.WriteHeader(http.StatusNotFound)
484
		}),
485
	)
486
	defer testServer.Close()
487
488
	socks5Server := startSocks5TestServer(t)
489
	defer socks5Server.Close()
490
491
	_, _, err = executeCommand(
492
		c,
493
		"scan",
494
		testServer.URL,
495
		"--dictionary",
496
		"testdata/dict.txt",
497
		"-v",
498
		"--http-timeout",
499
		"300",
500
		"--socks5",
501
		"127.0.0.1:9555", // invalid
502
	)
503
	assert.NoError(t, err)
504
505
	assert.Equal(t, 0, serverAssertion.Len())
506
	assert.Contains(t, loggerBuffer.String(), "failed to perform request")
507
	assert.Contains(t, loggerBuffer.String(), "socks connect tcp")
508
	assert.Contains(t, loggerBuffer.String(), "connect: connection refused")
509
}
510
511
func TestShouldFailToStartWithAnInvalidSocks5Address(t *testing.T) {
512
	logger, _ := test.NewLogger()
513
514
	c, err := createCommand(logger)
515
	assert.NoError(t, err)
516
	assert.NotNil(t, c)
517
518
	testServer, serverAssertion := test.NewServerWithAssertion(
519
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
520
			w.WriteHeader(http.StatusNotFound)
521
		}),
522
	)
523
	defer testServer.Close()
524
525
	_, _, err = executeCommand(
526
		c,
527
		"scan",
528
		testServer.URL,
529
		"--dictionary",
530
		"testdata/dict.txt",
531
		"-v",
532
		"--http-timeout",
533
		"300",
534
		"--socks5",
535
		"localhost%%2", // invalid
536
	)
537
	assert.Error(t, err)
538
	assert.Contains(t, err.Error(), "invalid URL escape")
539
540
	assert.Equal(t, 0, serverAssertion.Len())
541
}
542
543
func startSocks5TestServer(t *testing.T) net.Listener {
544
	conf := &socks5.Config{}
545
	server, err := socks5.New(conf)
546
	if err != nil {
547
		t.Fatalf("failed to create socks5: %s", err.Error())
548
	}
549
550
	listener, err := net.Listen("tcp", socks5TestServerHost)
551
	if err != nil {
552
		t.Fatalf("failed to create listener: %s", err.Error())
553
	}
554
555
	go func() {
556
		// Create SOCKS5 proxy on localhost port 8000
557
		if err := server.Serve(listener); err != nil {
558
			t.Logf("socks5 stopped serving: %s", err.Error())
559
		}
560
	}()
561
562
	return listener
563
}
564