Add credential embedding in stream URLs for SSE events
Embed username:password@ credentials in discovered stream URLs for basic_auth and combined authentication methods, making URLs directly usable by clients without additional auth handling. **Changes:** - Add embedCredentialsInURL() function in scanner.go - Embed credentials for basic_auth and combined methods only - Skip embedding for no_auth, query_params, digest, url_embedded - Handle edge cases: empty credentials, existing credentials in URL - Apply in scanDirectStream() and testURLsConcurrently() **Security:** - URL encoding handled by url.UserPassword() - Checks prevent credential duplication - Only processes when username AND password are provided **Results:** Before: http://10.0.20.112/snapshot.jpg After: http://admin:password@10.0.20.112/snapshot.jpg Tested with Zosi ZG23213M camera - all 6 streams working correctly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -178,8 +178,12 @@ func (s *Scanner) scanDirectStream(ctx context.Context, req models.StreamDiscove
|
||||
|
||||
if testResult.Working {
|
||||
result.TotalFound = 1
|
||||
|
||||
// Embed credentials in URL for basic_auth and combined methods
|
||||
finalURL := s.embedCredentialsInURL(testResult.URL, req.Username, req.Password, string(testResult.AuthMethod))
|
||||
|
||||
discoveredStream := models.DiscoveredStream{
|
||||
URL: testResult.URL,
|
||||
URL: finalURL,
|
||||
Type: testResult.Type,
|
||||
Protocol: testResult.Protocol,
|
||||
Working: true,
|
||||
@@ -231,6 +235,46 @@ func (s *Scanner) extractIP(target string) string {
|
||||
return target
|
||||
}
|
||||
|
||||
// embedCredentialsInURL embeds username and password in URL for basic_auth and combined methods
|
||||
func (s *Scanner) embedCredentialsInURL(streamURL, username, password, authMethod string) string {
|
||||
// Only apply for basic_auth and combined methods
|
||||
if authMethod != "basic_auth" && authMethod != "combined" {
|
||||
return streamURL
|
||||
}
|
||||
|
||||
// Check if credentials are provided
|
||||
if username == "" || password == "" {
|
||||
return streamURL
|
||||
}
|
||||
|
||||
// Parse URL
|
||||
u, err := url.Parse(streamURL)
|
||||
if err != nil {
|
||||
s.logger.Debug("failed to parse URL for credential embedding",
|
||||
"url", streamURL,
|
||||
"error", err.Error())
|
||||
return streamURL
|
||||
}
|
||||
|
||||
// Check if credentials already exist in URL
|
||||
if u.User != nil {
|
||||
s.logger.Debug("credentials already exist in URL, skipping embedding",
|
||||
"url", streamURL)
|
||||
return streamURL
|
||||
}
|
||||
|
||||
// Embed credentials
|
||||
u.User = url.UserPassword(username, password)
|
||||
embeddedURL := u.String()
|
||||
|
||||
s.logger.Debug("credentials embedded in URL",
|
||||
"original_url", streamURL,
|
||||
"embedded_url", embeddedURL,
|
||||
"auth_method", authMethod)
|
||||
|
||||
return embeddedURL
|
||||
}
|
||||
|
||||
// collectURLs collects all URLs to test
|
||||
func (s *Scanner) collectURLs(ctx context.Context, req models.StreamDiscoveryRequest, ip string) ([]string, error) {
|
||||
var allURLs []string
|
||||
@@ -444,8 +488,11 @@ func (s *Scanner) testURLsConcurrently(ctx context.Context, urls []string, req m
|
||||
if testResult.Working {
|
||||
atomic.AddInt32(&found, 1)
|
||||
|
||||
// Embed credentials in URL for basic_auth and combined methods
|
||||
finalURL := s.embedCredentialsInURL(testResult.URL, req.Username, req.Password, string(testResult.AuthMethod))
|
||||
|
||||
discoveredStream := models.DiscoveredStream{
|
||||
URL: testResult.URL,
|
||||
URL: finalURL,
|
||||
Type: testResult.Type,
|
||||
Protocol: testResult.Protocol,
|
||||
Port: 0, // Will be extracted from URL if needed
|
||||
|
||||
Reference in New Issue
Block a user