Files
cameradar/internal/attack/rtsp_url_test.go
T
Lawrence Arryl Lopez 8531c006d4 feat: support http tunneled rtsp (#419)
* 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>
2026-03-18 06:41:20 +01:00

165 lines
3.9 KiB
Go

package attack
import (
"net/netip"
"net/url"
"testing"
"github.com/Ullaakut/cameradar/v6"
"github.com/stretchr/testify/require"
)
func TestStreamURL(t *testing.T) {
tests := []struct {
name string
stream cameradar.Stream
wantURL string
wantParsedScheme string
}{
{
name: "empty route",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
},
wantURL: "rtsp://192.168.0.10:554/",
},
{
name: "root route",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"/"},
},
wantURL: "rtsp://192.168.0.10:554/",
},
{
name: "multiple leading slashes",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"////"},
},
wantURL: "rtsp://192.168.0.10:554/",
},
{
name: "route with no leading slash",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"stream"},
},
wantURL: "rtsp://192.168.0.10:554/stream",
},
{
name: "route with leading slash",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"/stream"},
},
wantURL: "rtsp://192.168.0.10:554/stream",
},
{
name: "route with trailing slash",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"stream/"},
},
wantURL: "rtsp://192.168.0.10:554/stream/",
},
{
name: "route with spaces",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{" /stream "},
},
wantURL: "rtsp://192.168.0.10:554/stream",
},
{
name: "username and password",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"stream"},
Username: "admin",
Password: "admin123",
},
wantURL: "rtsp://admin:admin123@192.168.0.10:554/stream",
},
{
name: "empty username with password",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"stream"},
Password: "pass",
},
wantURL: "rtsp://:pass@192.168.0.10:554/stream",
},
{
name: "username only",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"stream"},
Username: "user",
},
wantURL: "rtsp://user:@192.168.0.10:554/stream",
},
{
name: "http scheme",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"stream"},
Scheme: "http",
},
wantURL: "http://192.168.0.10:554/stream",
wantParsedScheme: "rtsp",
},
{
name: "https scheme",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"stream"},
Scheme: "https",
},
wantURL: "https://192.168.0.10:554/stream",
wantParsedScheme: "rtsps",
},
{
name: "rtsps scheme",
stream: cameradar.Stream{
Address: netip.MustParseAddr("192.168.0.10"),
Port: 554,
Routes: []string{"stream"},
Scheme: "rtsps",
},
wantURL: "rtsps://192.168.0.10:554/stream",
wantParsedScheme: "rtsps",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
gotURL := test.stream.String()
require.Equal(t, test.wantURL, gotURL)
parsedURL, err := test.stream.URL()
require.NoError(t, err)
expectedURL, err := url.Parse(test.wantURL)
require.NoError(t, err)
wantParsedScheme := test.wantParsedScheme
if wantParsedScheme == "" {
wantParsedScheme = expectedURL.Scheme
}
require.Equal(t, wantParsedScheme, parsedURL.Scheme)
})
}
}