package onvif import ( "fmt" "net/url" "os" "regexp" "strings" ) type Credentials struct { ONVIFUsername string ONVIFPassword string RTSPUsername string RTSPPassword string } type CredentialProvider interface { Resolve(reference string) (Credentials, error) } type EnvCredentials struct { LookupEnv func(string) (string, bool) } var credentialKey = regexp.MustCompile(`^[A-Za-z0-9_-]+$`) func (p EnvCredentials) Resolve(reference string) (Credentials, error) { parsed, err := url.Parse(reference) if err != nil || parsed.Scheme != "env" || parsed.User != nil || parsed.RawQuery != "" || parsed.Fragment != "" { return Credentials{}, fmt.Errorf("credential reference must use env://") } key := strings.Trim(strings.TrimSpace(parsed.Host+parsed.Path), "/") if !credentialKey.MatchString(key) { return Credentials{}, fmt.Errorf("credential reference contains an invalid key") } lookup := p.LookupEnv if lookup == nil { lookup = os.LookupEnv } prefix := "SENSE_CREDENTIAL_" + strings.ToUpper(strings.ReplaceAll(key, "-", "_")) read := func(suffix string) string { value, _ := lookup(prefix + suffix) return value } result := Credentials{ ONVIFUsername: read("_ONVIF_USERNAME"), ONVIFPassword: read("_ONVIF_PASSWORD"), RTSPUsername: read("_RTSP_USERNAME"), RTSPPassword: read("_RTSP_PASSWORD"), } if result.ONVIFUsername == "" || result.ONVIFPassword == "" { return Credentials{}, fmt.Errorf("ONVIF credentials are not configured for reference") } if result.RTSPUsername == "" { result.RTSPUsername = result.ONVIFUsername } if result.RTSPPassword == "" { result.RTSPPassword = result.ONVIFPassword } return result, nil }