8531c006d4
* enhancement: supporting http tunneled rtsp * refactor: simplify HTTP tunnel support per review feedback - Extract streamCandidate() for nmap port classification - Add isCommonHTTPPort() for masscan and nmap fallback - Move URL building to Stream.String() and Stream.URL() - Pass Stream directly to attack methods instead of individual args - Add TLS config for HTTPS tunnel support - Make auth detection non-fatal for tunneled streams - Rename HTTPTunnel to UseHTTPTunnel * - Testing the auth workflow for the tunneled streams is not blocking the rest of the pipeline since I changed the return values to Auth unknown and nil - added extra ports in the test according to suggestions * fixing some lint errors * removing the unused buildrtspurl * delayed the urlstream call for clarity removed error messages refactored the test that used the deprecated buildTRSPurl to use stream.URL and stream.String() methods * extracting iscommonHTTP port to pkg/ports (package ports) switching on u.scheme to create proper schemes for http and https * refactor: replace HTTP tunnel bool with scheme-based detection; enable TLS only for HTTPS-tunneled streams * chore: simnplify InferTunnelScheme and newRTSPClient * fix: remove rendundant check in streamCandidate * fix: typo in parseScheme * tests: coverage for new schemes * fix: use RTSP and not RTSPS for HTTPS URLs * fix: tunneled RTSP scheme handling and auth detection fallback * ui: render empty credentials as none in summary and TUI * chore: ignore duplicate-string warning for none literal * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix: rtsps probe headers --------- Co-authored-by: Brendan Le Glaunec <brendan@glaulabs.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
131 lines
3.2 KiB
Go
131 lines
3.2 KiB
Go
package ui_test
|
|
|
|
import (
|
|
"errors"
|
|
"net/netip"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/Ullaakut/cameradar/v6"
|
|
"github.com/Ullaakut/cameradar/v6/internal/ui"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestFormatSummary(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
streams []cameradar.Stream
|
|
err error
|
|
wantContains []string
|
|
wantNotContains []string
|
|
orderedPairs [][2]string
|
|
}{
|
|
{
|
|
name: "empty",
|
|
streams: nil,
|
|
wantContains: []string{
|
|
"Accessible streams: 0",
|
|
"• None",
|
|
},
|
|
wantNotContains: []string{
|
|
"Other discovered streams",
|
|
"Error:",
|
|
},
|
|
},
|
|
{
|
|
name: "mixed streams with error",
|
|
streams: []cameradar.Stream{
|
|
{
|
|
Device: "Model B",
|
|
Address: netip.MustParseAddr("10.0.0.2"),
|
|
Port: 554,
|
|
Available: true,
|
|
AuthenticationType: cameradar.AuthNone,
|
|
},
|
|
{
|
|
Device: "Model A",
|
|
Address: netip.MustParseAddr("10.0.0.1"),
|
|
Port: 8554,
|
|
Available: true,
|
|
Routes: []string{"stream1", "stream2"},
|
|
RouteFound: true,
|
|
CredentialsFound: true,
|
|
Username: "user",
|
|
Password: "pass",
|
|
AuthenticationType: cameradar.AuthBasic,
|
|
},
|
|
{
|
|
Address: netip.MustParseAddr("10.0.0.3"),
|
|
Port: 554,
|
|
Available: false,
|
|
AuthenticationType: cameradar.AuthDigest,
|
|
},
|
|
},
|
|
err: errors.New("boom"),
|
|
wantContains: []string{
|
|
"Accessible streams: 2",
|
|
"Other discovered streams: 1",
|
|
"• 10.0.0.1:8554 (Model A)",
|
|
"• 10.0.0.2:554 (Model B)",
|
|
"• 10.0.0.3:554",
|
|
"Authentication: basic",
|
|
"Authentication: none",
|
|
"Authentication: digest",
|
|
"Routes: stream1, stream2",
|
|
"Credentials: user:pass",
|
|
"Credentials: none",
|
|
"RTSP URL: rtsp://user:pass@10.0.0.1:8554/stream1",
|
|
"Admin panel: http://10.0.0.1/",
|
|
"Admin panel: http://10.0.0.2/",
|
|
},
|
|
wantNotContains: []string{
|
|
"Error:",
|
|
},
|
|
orderedPairs: [][2]string{
|
|
{"• 10.0.0.1:8554", "• 10.0.0.2:554"},
|
|
},
|
|
},
|
|
{
|
|
name: "empty discovered credentials render as none",
|
|
streams: []cameradar.Stream{
|
|
{
|
|
Address: netip.MustParseAddr("10.0.0.4"),
|
|
Port: 554,
|
|
Available: true,
|
|
RouteFound: true,
|
|
Routes: []string{"stream"},
|
|
CredentialsFound: true,
|
|
AuthenticationType: cameradar.AuthNone,
|
|
},
|
|
},
|
|
wantContains: []string{
|
|
"Accessible streams: 1",
|
|
"Credentials: none",
|
|
"RTSP URL: rtsp://10.0.0.4:554/stream",
|
|
},
|
|
wantNotContains: []string{
|
|
"Credentials: :",
|
|
"rtsp://:@10.0.0.4:554/stream",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
got := ui.FormatSummary(test.streams, test.err)
|
|
|
|
for _, expected := range test.wantContains {
|
|
assert.Contains(t, got, expected)
|
|
}
|
|
for _, unexpected := range test.wantNotContains {
|
|
assert.NotContains(t, got, unexpected)
|
|
}
|
|
for _, pair := range test.orderedPairs {
|
|
first := strings.Index(got, pair[0])
|
|
second := strings.Index(got, pair[1])
|
|
assert.True(t, first >= 0 && second >= 0 && first < second)
|
|
}
|
|
})
|
|
}
|
|
}
|