From 40b6fa4fcd2bfdcd94e6503f5152c670daf523a1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Mar 2026 14:00:16 -0400 Subject: [PATCH] fix: handle HTTP-to-HTTPS redirect in Reolink_HTTP login Reolink cameras may return a 302 redirect from HTTP to HTTPS. LWP::UserAgent does not follow redirects for POST requests, so the login would fail. Detect the redirect, update protocol/host/port from the Location header, disable SSL verification for self-signed camera certs, and retry the POST to the HTTPS endpoint. Subsequent API calls use the updated protocol. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../lib/ZoneMinder/Control/Reolink_HTTP.pm | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Reolink_HTTP.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Reolink_HTTP.pm index 2168602e8..01c9d89b8 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Reolink_HTTP.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Reolink_HTTP.pm @@ -86,6 +86,7 @@ sub open { $$self{username} = 'admin' unless $$self{username}; $$self{password} = '' unless $$self{password}; $$self{port} = 80 unless $$self{port}; + $$self{protocol} = 'http'; Debug("Reolink HTTP: Using credentials for $$self{host}:$$self{port}, user: $$self{username}"); @@ -133,16 +134,41 @@ sub login { }; my $json = encode_json([$login_cmd]); - my $url = 'http://'.$$self{host}.':'. $$self{port}.'/cgi-bin/api.cgi?cmd=Login&token=null'; - + my $url = $$self{protocol}.'://'.$$self{host}.':'.$$self{port}.'/cgi-bin/api.cgi?cmd=Login&token=null'; + $self->printMsg($json, 'Tx'); - + my $req = HTTP::Request->new(POST => $url); $req->content_type('application/json'); $req->content($json); - + my $res = $self->{ua}->request($req); - + + # Handle 302 redirect (camera redirecting HTTP to HTTPS) + if ($res->is_redirect) { + my $location = $res->header('Location'); + if ($location) { + Debug("Reolink login got redirect to: $location"); + my $redirect_uri = URI->new($location); + $$self{protocol} = $redirect_uri->scheme if $redirect_uri->scheme; + $$self{host} = $redirect_uri->host if $redirect_uri->host; + $$self{port} = $redirect_uri->port if $redirect_uri->port; + + # Disable SSL certificate verification for self-signed camera certs + if ($$self{protocol} eq 'https') { + $self->{ua}->ssl_opts(verify_hostname => 0, SSL_verify_mode => 0x00); + } + + # Retry with the redirected URL + $url = $$self{protocol}.'://'.$$self{host}.':'.$$self{port}.'/cgi-bin/api.cgi?cmd=Login&token=null'; + Debug("Reolink retrying login at: $url"); + $req = HTTP::Request->new(POST => $url); + $req->content_type('application/json'); + $req->content($json); + $res = $self->{ua}->request($req); + } + } + if ($res->is_success) { my $content = $res->decoded_content; Debug("Login response: $content"); @@ -223,7 +249,7 @@ sub sendApiCmd { $self->printMsg($json, 'Tx'); # Construct URL with token - my $url = 'http://'.$$self{host}.':'.$$self{port}.'/cgi-bin/api.cgi?cmd='.$cmds[0]->{cmd}.'&token='.$$self{token}; + my $url = $$self{protocol}.'://'.$$self{host}.':'.$$self{port}.'/cgi-bin/api.cgi?cmd='.$cmds[0]->{cmd}.'&token='.$$self{token}; my $req = HTTP::Request->new(POST => $url); $req->content_type('application/json');