Files
cameradar/cameradar.go
Brendan Le Glaunec e81eeb0c4d feat: v6 rewrite
2026-01-27 22:11:17 +01:00

79 lines
1.9 KiB
Go

package cameradar
import (
"context"
"errors"
"fmt"
)
// Reporter reports progress and results of the application.
type Reporter interface {
Start(step Step, message string)
Done(step Step, message string)
Error(step Step, err error)
Summary(streams []Stream, err error)
}
// App scans one or more targets and attacks all RTSP streams found to get their credentials.
type App struct {
streamScanner StreamScanner
attacker StreamAttacker
reporter Reporter
targets []string
ports []string
}
// StreamScanner discovers RTSP streams for the given inputs.
type StreamScanner interface {
Scan(ctx context.Context) ([]Stream, error)
}
// StreamAttacker attacks streams to discover routes and credentials.
type StreamAttacker interface {
Attack(ctx context.Context, streams []Stream) ([]Stream, error)
}
// New creates a new App with explicit dependencies.
func New(streamScanner StreamScanner, attacker StreamAttacker, targets, ports []string, reporter Reporter) (*App, error) {
if streamScanner == nil {
return nil, errors.New("stream scanner is required")
}
if attacker == nil {
return nil, errors.New("stream attacker is required")
}
app := &App{
streamScanner: streamScanner,
attacker: attacker,
targets: targets,
ports: ports,
reporter: reporter,
}
return app, nil
}
// Run runs the scan and prints the results.
func (a *App) Run(ctx context.Context) error {
a.reporter.Start(StepScan, "Scanning targets for RTSP streams")
streams, err := a.streamScanner.Scan(ctx)
if err != nil {
wrapped := fmt.Errorf("discovering devices: %w", err)
a.reporter.Error(StepScan, wrapped)
a.reporter.Summary(streams, wrapped)
return wrapped
}
a.reporter.Done(StepScan, "Scan complete")
streams, err = a.attacker.Attack(ctx, streams)
if err != nil {
wrapped := fmt.Errorf("attacking devices: %w", err)
a.reporter.Summary(streams, wrapped)
return wrapped
}
a.reporter.Summary(streams, nil)
return nil
}