koush / scrypted

Scrypted is a high performance video integration and automation platform
https://scrypted.app
Other
4.15k stars 247 forks source link

reolink: use Login json api to get around URL escaping limitations with some firmware #1509

Closed gtalusan closed 3 months ago

gtalusan commented 3 months ago

I noticed that I was unable to login to some of my cameras with Scrypted because my passwords have hyphens and spaces in them. In fact, the latest firmware available for my RLN36 NVR and CX410s requires the passwords to have passwords with mixed alpha-numeric and various symbols as can be seen from this screenshot:

Screenshot 2024-06-26 at 22 06 11

Here we'll switch over to using the Login API which has a JSON payload for the password. Each of the functions will check if the token has expired, and if so, we will re-perform the login to get a new token.

koush commented 3 months ago

does this login api exist on all reolink cameras

gtalusan commented 3 months ago

Yes, it appears in Version 1 2016-11 of their API documentation.

gtalusan commented 3 months ago

So to be clear, the code prior to the recent !skipValidation check worked for me. Switching to the JSON API should make it work for cameras stuck on older or unmaintained firmware.

koush commented 3 months ago

understood. this change would be better if you created a new method requestWithLogin and call login then request inside that, rather than duplicating the await login in every API call. then change all the API calls to requestWithLogin.

gtalusan commented 3 months ago

Ok, updated. I had to tighten up urlOrOptions to just be a bag of options and forced the code to use url as an actual URL object instead of a string, however the awkwardness is only within requestWithLogin.

koush commented 3 months ago

I just remembered that the simple password requirement extends to RTMP as well. The http login code here is only half the story. I think rolling back my change will start causing issues (again) with devices that can't accept complex passwords via RTMP. What reolink devices do you have on hand? I only have the doorbell. Incidentally I tried changing the doorbell to a complex password in their web admin... afterwards I couldn't log into the web admin anymore. Had to reset it.

gtalusan commented 3 months ago

Ah, ok, thanks for the heads up. I have CX410, RLN36 and the PoE doorbell. The CX410 and RLN36 have the stronger password requirement, and use the same password as my doorbell with hyphens and a space.

I took a quick at look at the getRtmpAddress code and put in some console.logs. The RTMP endpoint can take a token as a parameter according to the documentation and it works in my testing by hitting the RTSP rebroadcast URL. However, getConstructedVideoStreamOptionsInternal is only called once from what I can tell.

If the rebroadcast plugin needs to re-connect to the RTMP endpoint, does it call back into getConstructedVideoStreamOptions ? If so, then I think it'd be safe safe to perform a token refresh from that code path.

koush commented 3 months ago

getConstructedVideoStreamOptions should return fairly quickly. I actually don't think the token needs to be in the url returned there. the url doesn't need to be returned at all actually. getVideoStream should refresh the token.

gtalusan commented 3 months ago

Ok I'll dig a bit further.

koush commented 3 months ago

I think this function needs to be overridden to add the token:

https://github.com/koush/scrypted/blob/ea606de22f013a6c716aaf22aba3884cf08673ef/plugins/rtsp/src/rtsp.ts#L84

gtalusan commented 3 months ago

Ok, I overrode createVideoStream and addRtspCredentials to inject the token for rtmp:// URLs.

RTSP doesn't appear to support &token= in my testing.

koush commented 3 months ago

Ok, I overrode createVideoStream and addRtspCredentials to inject the token for rtmp:// URLs.

RTSP doesn't appear to support &token= in my testing.

RTSP likely requires the username and token as credentials and not parameters.

ie rtsp://username:token@192.168.2.222/....

gtalusan commented 3 months ago

Unfortunately not. Got a 401 Unauthorized.

koush commented 3 months ago

this change broke doorbell snapshots. reverting fixed it.

gtalusan commented 3 months ago

Interesting. Works here. Do you have any debug logs?

koush commented 3 months ago

it actually seems to be working now, after I reapplied the change. I was getting a json error before.

koush commented 3 months ago

it was broken again. not sure why, can't seem to catch it when it breaks. plugin reload fixes it.

koush commented 3 months ago

reported by another user as well. I switched to using username/password if it works, and falling back otherwise.