Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SendToHttp] Add option to add credentials in the URL #4145

Merged
merged 10 commits into from
Jul 22, 2022

Conversation

TD-er
Copy link
Member

@TD-er TD-er commented Jul 19, 2022

The hostname can now be:

  • hostname or IP
  • username:pass@hostname or IP

As reported on the forum

The hostname can now be:
- hostname or IP
- username:pass@hostname or IP
@TD-er
Copy link
Member Author

TD-er commented Jul 19, 2022

@thomastech Can you test this PR to see if it is now working for your cameras?

@thomastech
Copy link
Contributor

I manually patched the latest official release. The "SendToHTTP connection failed" log message is no longer seen. But the cameras still ignore the commands.

Here's my rules, which simply post an alternating ping/pong text message on the camera feed:

on WiFi#Connected do
  timerSet,1,5
  SendToHTTP,admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].EncodeBlend=true
endon

on Rules#Timer=1 do
  timerSet,2,15
  SendToHTTP,admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING1
endon

on Rules#Timer=2 do
  timerSet,1,15
  SendToHTTP admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG
endon

Here is the logs:

264014 : Info   : ACT  : timerSet,1,15
264015 : Debug  : Command: timerSet
264016 : Debug  : timerSet,1,15
264017 : Debug  : Par1: 1 Par2: 15 Par3: 0 Par4: 0 Par5: 0
264021 : Debug dev : RuleDebug: 000: SendToHTTP admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG
264022 : Info   : ACT  : SendToHTTP admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG
264024 : Debug  : Command: SendToHTTP
264025 : Debug  : SendToHTTP admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG
264026 : Debug  : Par1: 1073710336 Par2: 80 Par3: 1073709312 Par4: 0 Par5: 0
264028 : Info   : User:admin, Pass:cam123456
264029 : Debug  : SendToHTTP: Host: 192.168.1.240 port: 80
264030 : Debug  : SendToHTTP: Path: /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG
264051 : Debug  : GET /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG HTTP/1.1
Host: 192.168.1.240
Authorization: Basic YWRtaW46Y2FtMTIzNDU2
Accept: */*;q=0.1
User-Agent: ESP Easy/20116/Jul 19 2022 08:39:28
Connection: close

264052 : Debug  : GET /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG HTTP/1.1
Host: 192.168.1.240
Authorization: Basic YWRtaW46Y2FtMTIzNDU2
Accept: */*;q=0.1
User-Agent: ESP Easy/20116/Jul 19 2022 08:39:28
Connection: close

264053 : Debug  : HTTP : Command_HTTP_SendToHTTP written to client (252/252)
264054 : Debug  : HTTP : Command_HTTP_SendToHTTP closing connection
264070 : Debug  : EVENT: Rules#Timer=2,1 Processing time:75 milliSeconds
271847 : Info   : WD   : Uptime 5 ConnectFailures 0 FreeMem 17264 WiFiStatus WL_CONNECTED 3 ESPeasy internal wifi status: Conn. IP Init
271848 : Debug More : UDP  : Send Sysinfo message
272736 : Debug  : LoopStats: shortestLoop: 57 longestLoop: 895639 avgLoopDuration: 103.23 loopCounterMax: 526315 loopCounterLast: 277448
272737 : Debug  : Scheduler stats: (called/tasks/max_length/idle%) 277448/2129/7/94.18
279018 : Info   : EVENT: Rules#Timer=1,1
RuleDebug Processing:rules1.txt
     flags CMI  parse output:
279022 : Debug dev : RuleDebug: 011: on WiFi#Connected do
279023 : Debug dev : RuleDebug: 010: timerSet,1,5
279025 : Debug dev : RuleDebug: 010: SendToHTTP,admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].EncodeBlend=true
279028 : Debug dev : RuleDebug: 001: on Rules#Timer=1 do
279030 : Debug dev : RuleDebug: 000: timerSet,2,15
279031 : Info   : ACT  : timerSet,2,15
279034 : Debug  : Command: timerSet
279035 : Debug  : timerSet,2,15
279036 : Debug  : Par1: 2 Par2: 15 Par3: 0 Par4: 0 Par5: 0
279040 : Debug dev : RuleDebug: 000: SendToHTTP,admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING1
279042 : Info   : ACT  : SendToHTTP,admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING1
279045 : Debug  : Command: SendToHTTP
279045 : Debug  : SendToHTTP,admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING1
279046 : Debug  : Par1: 1073710080 Par2: 80 Par3: 1073708800 Par4: 0 Par5: 0
279048 : Info   : User:admin, Pass:cam123456
279049 : Debug  : SendToHTTP: Host: 192.168.1.240 port: 80
279051 : Debug  : SendToHTTP: Path: /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING1
279077 : Debug  : GET /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING1 HTTP/1.1
Host: 192.168.1.240
Authorization: Basic YWRtaW46Y2FtMTIzNDU2
Accept: */*;q=0.1
User-Agent: ESP Easy/20116/Jul 19 2022 08:39:28
Connection: close

279078 : Debug  : GET /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING1 HTTP/1.1
Host: 192.168.1.240
Authorization: Basic YWRtaW46Y2FtMTIzNDU2
Accept: */*;q=0.1
User-Agent: ESP Easy/20116/Jul 19 2022 08:39:28
Connection: close

279080 : Debug  : HTTP : Command_HTTP_SendToHTTP written to client (253/253)
279080 : Debug  : HTTP : Command_HTTP_SendToHTTP closing connection
279107 : Debug  : EVENT: Rules#Timer=1,1 Processing time:89 milliSeconds
294037 : Info   : EVENT: Rules#Timer=2,1

I've also tested with the "SendToHTTP wait for ack" enabled in advanced settings.

BTW, using "bad" credentials does not change the log messages. So hard to know if my bad fortune is a credential arg or command arg issue. But as discussed before, sending the commands as a URL in a browser is always successful. Success is reported as "OK" in the browser window.

Lastly, the logs do not have the "WiFi : Set TX power to " messages. Those are horrific spammers, so I had to suppress them.

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 19, 2022

Lastly, the logs do not have the "WiFi : Set TX power to " messages. Those are horrific spammers, so I had to suppress them.

Those can be disabled by setting the WiFi TX power to always use max power.
I have converted the credentials to basic auth (MD5 encoded "user:pass").
Maybe your camera doesn't support/accept this.

Can you try to get a Wireshark dump when trying to send the same URL from your browser?

@thomastech
Copy link
Contributor

Good to know that the logged Tx power messages can be disabled via the web interface.

My cameras require basic auth (base64 encoded), so you did the right thing. Please see section 3.2 in this doc for details:
https://community.jeedom.com/uploads/short-url/tTQJPaNah7gZnU12VGGN9ZHEhOk.pdf

I tried Wireshark years ago and gave up on it. But I'll install it again and post a dump.

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 19, 2022

I tried Wireshark years ago and gave up on it. But I'll install it again and post a dump.

Make sure to only include data to/from that host.
If unsure whether it may contain other data, you can send the log to me personally.

@thomastech
Copy link
Contributor

thomastech commented Jul 19, 2022

I appreciate the concern about sensitive data. I don't see any, so hopefully the posted info is safe.

Here's some filtered data (ip.dst == 192.168.1.240) that we can start with (local PC is *.175, camera is *.240):

No.     Time           Source                Destination           Protocol Length Info
     51 4.280530       192.168.1.175         192.168.1.240         TCP      66     58864 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM=1

Frame 51: 66 bytes on wire (528 bits), 66 bytes captured (528 bits) on interface \Device\NPF_{E9016CA9-A6D6-4720-959E-1A3EA6AC0146}, id 0
Ethernet II, Src: ASRockIn_22:e1:82 (70:85:c2:22:e1:82), Dst: AmcrestT_27:96:a5 (9c:8e:cd:27:96:a5)
Internet Protocol Version 4, Src: 192.168.1.175, Dst: 192.168.1.240
Transmission Control Protocol, Src Port: 58864, Dst Port: 80, Seq: 0, Len: 0

No.     Time           Source                Destination           Protocol Length Info
     52 4.280875       192.168.1.175         192.168.1.240         TCP      66     58865 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM=1

Frame 52: 66 bytes on wire (528 bits), 66 bytes captured (528 bits) on interface \Device\NPF_{E9016CA9-A6D6-4720-959E-1A3EA6AC0146}, id 0
Ethernet II, Src: ASRockIn_22:e1:82 (70:85:c2:22:e1:82), Dst: AmcrestT_27:96:a5 (9c:8e:cd:27:96:a5)
Internet Protocol Version 4, Src: 192.168.1.175, Dst: 192.168.1.240
Transmission Control Protocol, Src Port: 58865, Dst Port: 80, Seq: 0, Len: 0

No.     Time           Source                Destination           Protocol Length Info
     54 4.281470       192.168.1.175         192.168.1.240         TCP      54     58865 → 80 [ACK] Seq=1 Ack=1 Win=262656 Len=0

Frame 54: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \Device\NPF_{E9016CA9-A6D6-4720-959E-1A3EA6AC0146}, id 0
Ethernet II, Src: ASRockIn_22:e1:82 (70:85:c2:22:e1:82), Dst: AmcrestT_27:96:a5 (9c:8e:cd:27:96:a5)
Internet Protocol Version 4, Src: 192.168.1.175, Dst: 192.168.1.240
Transmission Control Protocol, Src Port: 58865, Dst Port: 80, Seq: 1, Ack: 1, Len: 0

No.     Time           Source                Destination           Protocol Length Info
     55 4.282962       192.168.1.175         192.168.1.240         HTTP     610    GET /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED HTTP/1.1 

Frame 55: 610 bytes on wire (4880 bits), 610 bytes captured (4880 bits) on interface \Device\NPF_{E9016CA9-A6D6-4720-959E-1A3EA6AC0146}, id 0
Ethernet II, Src: ASRockIn_22:e1:82 (70:85:c2:22:e1:82), Dst: AmcrestT_27:96:a5 (9c:8e:cd:27:96:a5)
Internet Protocol Version 4, Src: 192.168.1.175, Dst: 192.168.1.240
Transmission Control Protocol, Src Port: 58865, Dst Port: 80, Seq: 1, Ack: 1, Len: 556
Hypertext Transfer Protocol
    GET /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): GET /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED HTTP/1.1\r\n]
        Request Method: GET
        Request URI: /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED
            Request URI Path: /cgi-bin/configManager.cgi
            Request URI Query: action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED
                Request URI Query Parameter: action=setConfig
                Request URI Query Parameter: VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED
        Request Version: HTTP/1.1
    Host: 192.168.1.240\r\n
    Connection: keep-alive\r\n
    Upgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n
    Accept-Encoding: gzip, deflate\r\n
    Accept-Language: en-US,en;q=0.9\r\n
    Cookie: secure; username=admin\r\n
    \r\n
    [Full request URI: http://192.168.1.240/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED]
    [HTTP request 1/1]
    [Response in frame: 59]

No.     Time           Source                Destination           Protocol Length Info
     58 4.283501       192.168.1.175         192.168.1.240         TCP      54     58864 → 80 [ACK] Seq=1 Ack=1 Win=262656 Len=0

Frame 58: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \Device\NPF_{E9016CA9-A6D6-4720-959E-1A3EA6AC0146}, id 0
Ethernet II, Src: ASRockIn_22:e1:82 (70:85:c2:22:e1:82), Dst: AmcrestT_27:96:a5 (9c:8e:cd:27:96:a5)
Internet Protocol Version 4, Src: 192.168.1.175, Dst: 192.168.1.240
Transmission Control Protocol, Src Port: 58864, Dst Port: 80, Seq: 1, Ack: 1, Len: 0

No.     Time           Source                Destination           Protocol Length Info
     61 4.295479       192.168.1.175         192.168.1.240         TCP      54     58865 → 80 [ACK] Seq=557 Ack=242 Win=2102272 Len=0

Frame 61: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \Device\NPF_{E9016CA9-A6D6-4720-959E-1A3EA6AC0146}, id 0
Ethernet II, Src: ASRockIn_22:e1:82 (70:85:c2:22:e1:82), Dst: AmcrestT_27:96:a5 (9c:8e:cd:27:96:a5)
Internet Protocol Version 4, Src: 192.168.1.175, Dst: 192.168.1.240
Transmission Control Protocol, Src Port: 58865, Dst Port: 80, Seq: 557, Ack: 242, Len: 0

No.     Time           Source                Destination           Protocol Length Info
     62 4.296180       192.168.1.175         192.168.1.240         TCP      54     58865 → 80 [FIN, ACK] Seq=557 Ack=242 Win=2102272 Len=0

Frame 62: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \Device\NPF_{E9016CA9-A6D6-4720-959E-1A3EA6AC0146}, id 0
Ethernet II, Src: ASRockIn_22:e1:82 (70:85:c2:22:e1:82), Dst: AmcrestT_27:96:a5 (9c:8e:cd:27:96:a5)
Internet Protocol Version 4, Src: 192.168.1.175, Dst: 192.168.1.240
Transmission Control Protocol, Src Port: 58865, Dst Port: 80, Seq: 557, Ack: 242, Len: 0

No.     Time           Source                Destination           Protocol Length Info
     63 4.296348       192.168.1.175         192.168.1.240         HTTP     957    GET /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED HTTP/1.1 

Frame 63: 957 bytes on wire (7656 bits), 957 bytes captured (7656 bits) on interface \Device\NPF_{E9016CA9-A6D6-4720-959E-1A3EA6AC0146}, id 0
Ethernet II, Src: ASRockIn_22:e1:82 (70:85:c2:22:e1:82), Dst: AmcrestT_27:96:a5 (9c:8e:cd:27:96:a5)
Internet Protocol Version 4, Src: 192.168.1.175, Dst: 192.168.1.240
Transmission Control Protocol, Src Port: 58864, Dst Port: 80, Seq: 1, Ack: 1, Len: 903
Hypertext Transfer Protocol
    GET /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): GET /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED HTTP/1.1\r\n]
        Request Method: GET
        Request URI: /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED
            Request URI Path: /cgi-bin/configManager.cgi
            Request URI Query: action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED
                Request URI Query Parameter: action=setConfig
                Request URI Query Parameter: VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED
        Request Version: HTTP/1.1
    Host: 192.168.1.240\r\n
    Connection: keep-alive\r\n
     [truncated]Authorization: Digest username="admin", realm="Login to AMC060FA9E5447CE86", nonce="764626010", uri="/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED", response="23eff0056a21c98
         username="admin"
         realm="Login to AMC060FA9E5447CE86"
         nonce="764626010"
         uri="/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED"
         response="23eff0056a21c98b87afe8ec8595acfd"
         opaque="2f86f3037c66bf15cdd6dc40cb9bea20e731bf7a"
         qop=auth
         nc=00000001
    Upgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n
    Accept-Encoding: gzip, deflate\r\n
    Accept-Language: en-US,en;q=0.9\r\n
    Cookie: secure; username=admin\r\n
    \r\n
    [Full request URI: http://192.168.1.240/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=DOOR%20IS%20LOCKED]
    [HTTP request 1/1]
    [Response in frame: 69]

No.     Time           Source                Destination           Protocol Length Info
     71 4.566265       192.168.1.175         192.168.1.240         TCP      54     58864 → 80 [ACK] Seq=904 Ack=329 Win=262400 Len=0

Frame 71: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \Device\NPF_{E9016CA9-A6D6-4720-959E-1A3EA6AC0146}, id 0
Ethernet II, Src: ASRockIn_22:e1:82 (70:85:c2:22:e1:82), Dst: AmcrestT_27:96:a5 (9c:8e:cd:27:96:a5)
Internet Protocol Version 4, Src: 192.168.1.175, Dst: 192.168.1.240
Transmission Control Protocol, Src Port: 58864, Dst Port: 80, Seq: 904, Ack: 329, Len: 0

No.     Time           Source                Destination           Protocol Length Info
     72 4.566570       192.168.1.175         192.168.1.240         TCP      54     58864 → 80 [FIN, ACK] Seq=904 Ack=329 Win=262400 Len=0

Frame 72: 54 bytes on wire (432 bits), 54 bytes captured (432 bits) on interface \Device\NPF_{E9016CA9-A6D6-4720-959E-1A3EA6AC0146}, id 0
Ethernet II, Src: ASRockIn_22:e1:82 (70:85:c2:22:e1:82), Dst: AmcrestT_27:96:a5 (9c:8e:cd:27:96:a5)
Internet Protocol Version 4, Src: 192.168.1.175, Dst: 192.168.1.240
Transmission Control Protocol, Src Port: 58864, Dst Port: 80, Seq: 904, Ack: 329, Len: 0


@thomastech
Copy link
Contributor

thomastech commented Jul 19, 2022

From the ESPEasy Device the camera commands are sent every 15 secs via the timer rules. But the camera's IP does not show any ESPEasy related http activity in Wireshark.

The ESPEasy WiFi device is at 192.168.1.20 and the POE Ethernet camera is at 192.168.1.240. I have filtering set to ip.dst == 192.168.1.240.

Is it possible for Wireshark to monitor WiFi and/or Ethernet data that's not sent or received by my PC? Advice on how to do this would be great.

BTW, I did not install any controllers or plugins. Do I need to install a HTTP controller to use the sendToHTTP?

  • Thomas

@tonhuisman
Copy link
Contributor

Do I need to install a HTTP controller to use the sendToHTTP?

No, not for HTTP, a Controller is only needed for MQTT, because of the different server protocols / formats used.

@TD-er
Copy link
Member Author

TD-er commented Jul 19, 2022

I think you can also filter with Wireshark using (ip.dst == 192.168.1.240 || ip.src == 192.168.1.240)
But if I remember correctly, Wireshark also has a "filter creator wizard" or whatever it is called.

Anyway, it seems your browser is not using the basic authentication.

@thomastech
Copy link
Contributor

thomastech commented Jul 19, 2022

I think you can also filter with Wireshark using (ip.dst == 192.168.1.240 || ip.src == 192.168.1.240)
But if I remember correctly, Wireshark also has a "filter creator wizard" or whatever it is called.

I'm only able to capture 255.255.255.255 UDP data from the ESPEasy Device. I haven't found the magic words that allow me to monitor its http traffic going directly to the camera. No worries, I'll skip this for now.

Anyway, it seems your browser is not using the basic authentication.

Is this a nice way of saying that I'm out of luck? Or do you have any other secrete weapons for me to try?

EDIT: I'll try the latest commit.

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 19, 2022

@thomastech Can you try again with the latest commit I added to this PR?
It now uses the same code as is used for "Controller Plugin 011: Generic HTTP Advanced"

@TD-er
Copy link
Member Author

TD-er commented Jul 19, 2022

Is this a nice way of saying that I'm out of luck? Or do you have any other secrete weapons for me to try?

See my last post I made almost at the same moment as your post.

@thomastech
Copy link
Contributor

thomastech commented Jul 19, 2022

Installed the latest HTTP.cpp

Not working yet. I see a http 401 in the log messages. Here's an excerpt:

RuleDebug Processing:rules1.txt
     flags CMI  parse output:
332168 : Debug dev : RuleDebug: 011: on Wifi#Connected do
332169 : Debug dev : RuleDebug: 010: timerSet,1,10
332171 : Debug dev : RuleDebug: 011: on Rules#Timer=1 do
332173 : Debug dev : RuleDebug: 010: timerSet,2,15
332174 : Debug dev : RuleDebug: 010: SendToHTTP admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING
332177 : Debug dev : RuleDebug: 001: on Rules#Timer=2 do
332179 : Debug dev : RuleDebug: 000: timerSet,1,15
332180 : Info   : ACT  : timerSet,1,15
332182 : Debug  : Command: timerSet
332183 : Debug  : timerSet,1,15
332183 : Debug  : Par1: 1 Par2: 15 Par3: 0 Par4: 0 Par5: 0
332187 : Debug dev : RuleDebug: 000: SendToHTTP,admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG
332188 : Info   : ACT  : SendToHTTP,admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG
332193 : Debug  : Command: SendToHTTP
332193 : Debug  : SendToHTTP,admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG
332194 : Debug  : Par1: 1073702144 Par2: 80 Par3: 1073702400 Par4: 0 Par5: 0
332197 : Debug  : SendToHTTP: Host: 192.168.1.240 port: 80
332198 : Debug  : SendToHTTP: Path: /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG
332230 : Error  : HTTP : Command_HTTP_SendToHTTP GET... HTTP code: 401
332232 : Info   : SendToHTTP: 401
332232 : Error  : SendToHTTP: HTTP code: 401
332236 : Debug  : EVENT: Rules#Timer=2,1 Processing time:73 milliSeconds
332716 : Debug  : LoopStats: shortestLoop: 60 longestLoop: 4419568 avgLoopDuration: 76.40 loopCounterMax: 500000 loopCounterLast: 369779
332717 : Debug  : Scheduler stats: (called/tasks/max_length/idle%) 369779/2124/7/93.71
347185 : Info   : EVENT: Rules#Timer=1,1
RuleDebug Processing:rules1.txt
     flags CMI  parse output:
347190 : Debug dev : RuleDebug: 011: on Wifi#Connected do
347191 : Debug dev : RuleDebug: 010: timerSet,1,10
347193 : Debug dev : RuleDebug: 001: on Rules#Timer=1 do
347195 : Debug dev : RuleDebug: 000: timerSet,2,15
347196 : Info   : ACT  : timerSet,2,15
347198 : Debug  : Command: timerSet
347199 : Debug  : timerSet,2,15
347200 : Debug  : Par1: 2 Par2: 15 Par3: 0 Par4: 0 Par5: 0
347203 : Debug dev : RuleDebug: 000: SendToHTTP admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING
347205 : Info   : ACT  : SendToHTTP admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING
347207 : Debug  : Command: SendToHTTP
347208 : Debug  : SendToHTTP admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING
347209 : Debug  : Par1: 1073702144 Par2: 80 Par3: 1073705472 Par4: 0 Par5: 0
347211 : Debug  : SendToHTTP: Host: 192.168.1.240 port: 80
347212 : Debug  : SendToHTTP: Path: /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING
347271 : Error  : HTTP : Command_HTTP_SendToHTTP GET... HTTP code: 401
347273 : Info   : SendToHTTP: 401
347273 : Error  : SendToHTTP: HTTP code: 401
347277 : Debug  : EVENT: Rules#Timer=1,1 Processing time:92 milliSeconds
358665 : Info   : EVENT: Clock#Time=Tue,14:23
RuleDebug Processing:rules1.txt
     flags CMI  parse output:
358669 : Debug dev : RuleDebug: 011: on Wifi#Connected do
358670 : Debug dev : RuleDebug: 010: timerSet,1,10
358673 : Debug dev : RuleDebug: 011: on Rules#Timer=1 do
358674 : Debug dev : RuleDebug: 010: timerSet,2,15
358676 : Debug dev : RuleDebug: 010: SendToHTTP admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING
358678 : Debug dev : RuleDebug: 011: on Rules#Timer=2 do
358680 : Debug dev : RuleDebug: 010: timerSet,1,15
358681 : Debug dev : RuleDebug: 010: SendToHTTP,admin:cam123456@192.168.1.240,80,/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG
358684 : Debug  : EVENT: Clock#Time=Tue,14:23 Processing time:19 milliSeconds
361826 : Info   : WD   : Uptime 6 ConnectFailures 0 FreeMem 17976 WiFiStatus WL_CONNECTED 3 ESPeasy internal wifi status: Conn. IP Init
361827 : Debug More : UDP  : Send Sysinfo message
362201 : Info   : EVENT: Rules#Timer=2,1

EDIT:

Anyway, it seems your browser is not using the basic authentication.

Agreed, I noticed that it uses digest authorization. The camera's API Document summarizes both (basic and digest) auth steps, summarized as follows:

The IP Camera supplies two authentication ways: basic authentication and digest authentication. Client can login through:
http://<ip>/cgi-bin/global.login?userName=admin. The IP camera returns 401. Then the client inputs a username and password to authorize.
For example:
1. When basic authentication, the IP camera response:
401 Unauthorized
WWW-Authenticate: Basic realm=”XXXXXX”
Then the client encode the username and password with base64, send the following request:
Authorization: Basic VXZVXZ.
2. When digest authentication, the IP camera response:
WWW-Authenticate: Digest realm="DH_00408CA5EA04", nonce="000562fdY631973ef04f77a3ede7c1832ff48720ef95ad",
stale=FALSE, qop="auth";
The client calculates the digest using username, password, nonce, realm and URI with MD5, then send the following request:
Authorization: Digest username="admin", realm="DH_00408CA5EA04", nc=00000001,cnonce="0a4f113b",qop="auth"
nonce="000562fdY631973ef04f77a3ede7c1832ff48720ef95ad",uri="cgi-bin/global.login?userName=admin",
response="65002de02df697e946b750590b44f8b

So a 401 Unauthorized message is expected. But the client response needs to be a base64 encoded user and password. Any advise on doing that would be appreciated.

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 20, 2022

[...]

So a 401 Unauthorized message is expected. But the client response needs to be a base64 encoded user and password. Any advise on doing that would be appreciated.

I am sending the base64 encoded user/pass:
image

Only difference seems to be that I send it in the header and the text suggests to send it as a response.

@TD-er
Copy link
Member Author

TD-er commented Jul 20, 2022

OK, got some ideas here...

  • Try using a browser (or incognito mode) which may not have cached the credentials
  • Try to access the camera using the url with user and pass included in the URL

If that fails, I guess the camera really expects a host to call the http://<ip>/cgi-bin/global.login?userName=admin url first and then respond with the credentials encoded.
You can also do this in ESPEasy by calling the same login URL first and then the one you need to send your "GET" request.

@thomastech
Copy link
Contributor

OK, got some ideas here...
Try using a browser (or incognito mode) which may not have cached the credentials
Try to access the camera using the url with user and pass included in the URL

That's what I'm doing in my browsers tests. Works fine.

If that fails, I guess the camera really expects a host to call the http:///cgi-bin/global.login?userName=admin url first and then respond with the credentials encoded.

The camera's login is an alternate way to send the credentials. I don't think anyone does it that way because it's more efficient to include the credentials with a command instead. But I've tried it this way and as before, works in a browser but not ESPEasy.

Only difference seems to be that I send it in the header and the text suggests to send it as a response.

According to my searches on authentication, the credentials are suppose to be sent as a response to the 401. This acts as a challenge and it provides the response format. So it seems the camera is following the typical base auth method.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 20, 2022

Well I tried it on some other devices and they accept the credentials in the header, even if it is the first query from that host.

Have you tried to 'fake' accessing the login page by a separate call using sendtohttp and then the actual url you need with the credentials?

sendtohttp,<ip>,80,/cgi-bin/global.login?userName=admin
sendtohttp,admin:passwd@<ip>,80,/foo/bar/showsometextoverlay/bla

@thomastech
Copy link
Contributor

thomastech commented Jul 21, 2022

@TD-er, thanks for the continued support. I appreciate your advice.

Today I spent several hours tweaking ESPEasy basic auth code with the hope of finding a solution. Plus there was a lot of searching through github and tech forums. Late this afternoon I finally found the reason for all this frustration.

Spoiler: The camera's API docs don't mention that basic authorization was disabled on recent firmware. Dahua and Amcrest cameras (the two brands I use) now default to Digest Authorization. Apparently this was done to improve security. And as usual I didn't get the memo.

I would volunteer adding the Digest Auth feature to ESPEasy, but I don't think I'm the right guy for the job. But I can certainly help with test/validation. :)

And for sure, thanks for all the help and advice. Would never have found the reason for why it does not work without your assistance.

  • Thomas

@thomastech
Copy link
Contributor

BTW, while I was hacking/modifying code I found that the http.getString() library function used in send_via_http() is broken (see _CPlugin_Helper.cpp). It only returns empty strings on my ESP8266 build. In a perfect world the returned http GET payload message would indicate if basic versus digest authorization is required by the device.

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 21, 2022

Thanks for the update.
I will look into it.
Not sure if we can see if a host only accepts Digest Authorization or simply have to test one and then retry using the other.
This is rather inefficient.
So maybe we need to either cache it, or use a parameter (or setting?) or a new command to make clear which one to use.

@thomastech
Copy link
Contributor

Not sure if we can see if a host only accepts Digest Authorization or simply have to test one and then retry using the other.

There's a built-in mechanism for that. When the host returns the 401 error it also provides a payload that reports which authorization method to use. This message can be used to select the correct one.

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 21, 2022

Not sure if we can see if a host only accepts Digest Authorization or simply have to test one and then retry using the other.

There's a built-in mechanism for that. When the host returns the 401 error it also provides a payload that reports which authorization method to use. This message can be used to select the correct one.

  • Thomas

Do you have a link or dump on what string will be returned?

@thomastech
Copy link
Contributor

Basic Auth payload example:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm=”XXXXXX”

Digest Auth payload example:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest realm="XXXXXX", nonce="000562fdY631973ef04f77a3ede7c1832ff48720ef95ad", stale=FALSE, qop="auth"

Note: The client calculates the digest authorization using the payload information. The username, password, nonce, HTTP method and URI are hashed with MD5, and then sends it back to the server.

The protocol is well documented for both methods. For example, some details can be found here:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication

BTW: As previously mentioned, the send_via_http() function makes a call to http.getString(), which should return this special payload. But getString() returns an empty string on my ESP8266 builds (did not try ESP32).

I found the ESP8266HTTPClient.h header file (for getString) is missing. This does not cause a build error because it appears a pre-compiled library is used instead. That's as far as I got with my debug efforts to find the reason for the missing http GET payload. If you can get it functional I will capture a real payload from my camera to use as a reference.

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 21, 2022

OK, added some code based on example code.
Not tested, the state of the code is: It compiles.

So please let me know if this is working, or at least not blowing up your ESP.

@thomastech
Copy link
Contributor

Wow, you work fast! Added the changes and the ESP8266 is running. But the camera is not responding to the text overlay commands. I have a feeling that will come soon.

Your commit is correctly detecting the Digest Auth. Here's the log:

263149 : Debug  : SendToHTTP: Host: 192.168.1.240 port: 80
263150 : Debug  : SendToHTTP: Path: /cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PING
263189 : Info   : HTTP : Start Digest Authorization for 192.168.1.240
263446 : Error  : HTTP : Command_HTTP_SendToHTTP GET... HTTP code: 401
263447 : Info   : SendToHTTP: 401
263448 : Error  : SendToHTTP: HTTP code: 401

Here is the 401 Unauthorized payload that is returned by the camera:
Digest realm="Login to AMC060FA9E5447CE86", qop="auth", nonce="870658570", opaque="2f86f3037c66bf15cdd6dc40cb9bea20e731bf7a"

Here are the authorization variables used in getDigestAuth():
Digest username="admin", realm="Login to AMC060FA9E5447CE86", nonce="870658570", uri="/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].Text=PONG", algorithm="MD5", qop=auth, nc=00000001, cnonce="zFVYIwl6", response="72e30a5a95a1f003b2ecce513101cd2a"

  • Thomas

@thomastech
Copy link
Contributor

It's working! The test camera's image now has a text message that toggles between "PING" and "PONG". So your Digest Auth code is a success.

I need to shutdown for the day. So I'll post some details for your refreshed eyes while mine are still counting sheep.

Here is what I found:

The http.addHeader() function was not working with the Authorization keyword name. My temporary fix was to add this statement before calling it (see file_CPlugin_Helper.cpp):

http.setAuthorization("");

So the updated code snippet looks like this :

#endif // if defined(CORE_POST_2_6_0) || defined(ESP32)

      http.setAuthorization("");
      http.addHeader(F("Authorization"), authorization);

      // start connection and send HTTP header (and body)

It's clear what this temporary fix is doing (TL;DR, zeros the string length). But I don't know if nulling the _base64Authorization var should remain a final solution. But the little details certainly point to what needs your further code review.

Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 22, 2022

OK, that makes sense.
I guess I will even destruct the http object and create it again, just to be sure nothing else may be left.
It also allows me to get rid of the code duplication.

Maybe if this works, we can also start automating the sheep counting. That will save a lot of time ;)

This also fixes a timeout issue on ESP32 as the WiFiClient timeout is set in seconds (!!!!!)

See: espressif/arduino-esp32#6676

Extremely frustrating design choice as it has taken extreme amounts of time to debug those issues!
@thomastech
Copy link
Contributor

I applied your latest commit (updated 11 files). Compiles and runs. I'm using a Wemos D1 Mini with NORMAL_ESP8266_4M1M. No plugins or controllers, just rules and NTP.

BTW, I've tested another command (Day/Night Profile switching) on a Amcrest 5MP Turret camera. Success. So Digest Auth is working with Dahua and Amcrest brand cameras (they are both made by Dahua).

Thanks again for adding Basic and Digest Auth. I'm surprised I'm the only one that has asked for this. And feel very fortunate that you added it so quickly. Looking forward to seeing it in a future Mega release.

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 22, 2022

I also adapted all http-related plugins to use this function.
So those have to be checked too.

And there was apparently a very nasty design choice on ESP32 which does set the timeout in seconds instead of msec as is done everywhere else.
So hopefully that's now also causing less issues on ESP32.

@TD-er
Copy link
Member Author

TD-er commented Jul 22, 2022

By the way, should I also create an event with the result of the HTTP call?

@thomastech
Copy link
Contributor

I also adapted all http-related plugins to use this function.
So those have to be checked too.

Unfortunately I don't have any other http devices for the validation. I could test MQTT, does that help?

should I also create an event with the result of the HTTP call?

Maybe. Can you explain what this would do and how it is used?

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 22, 2022

Unfortunately I don't have any other http devices for the validation. I could test MQTT, does that help?

Nope, MQTT controllers won't use this function call.

Maybe. Can you explain what this would do and how it is used?

You can see it as some kind of "return value" so there will be an event with the last return value.

For example something like this: http#hostname=401

@thomastech
Copy link
Contributor

For example something like this: http#hostname=401

Yes, that's useful. Returning the httpCode would be a nice touch.

I expect that successful sendToHTTP would return code 200 (OK). And that value could be used by the rules to verify success.

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 22, 2022

Yep, that's the idea :)

@thomastech
Copy link
Contributor

thomastech commented Jul 22, 2022

Tested latest commit (2 changed files). The http return code feature is working.

Here is the rule I used to validate it:

on http#192.168.1.240 do
  logentry,"HTTP CODE IS %eventvalue1%"
  if %eventvalue1%=200
   logentry,"---->Success"
  else
   logentry,"---->FAIL!"
  endif
endon

Tested both valid and invalid credentials. Success is code 200, failure is 401. Invalid camera command returns code 400. All good, just as expected.

  • Thomas

@TD-er
Copy link
Member Author

TD-er commented Jul 22, 2022

Thanks for testing

@TD-er TD-er merged commit e2c98cf into letscontrolit:mega Jul 22, 2022
@TD-er TD-er deleted the bugfix/sendtohttp_credentials branch July 22, 2022 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants