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

get_liveview() returns a immis protocol link #343

Open
IanTrudel opened this issue Jul 26, 2020 · 21 comments
Open

get_liveview() returns a immis protocol link #343

IanTrudel opened this issue Jul 26, 2020 · 21 comments
Labels
help-wanted Assistance required due to lack of resources for testing or complexity

Comments

@IanTrudel
Copy link

get_liveview() returns a immis link on an XT2 camera instead of an rtsps link. The only information on the protocol that I could find is on lurume84/bling-desktop#26. Any (other) way to access the stream?

@fronzbot
Copy link
Owner

Not that I'm aware, sorry

@fronzbot fronzbot added the help-wanted Assistance required due to lack of resources for testing or complexity label Aug 2, 2020
@e-team-t
Copy link

e-team-t commented Aug 5, 2020

get_liveview() return the following for me on a xt2 ,

.local/lib/python3.6/site-packages/blinkpy/camera.py", line 204, in get_liveview
    return response["server"]
KeyError: 'server'

Also tried this:
blinkpy.api.request_camera_liveview( blink, ...
Got the following in return:
{'message': 'An app update is required'}

any ideas?

@fronzbot
Copy link
Owner

fronzbot commented Aug 5, 2020

Yeah looks like the API endpoint changed. This guy figured it out recently so looks like that link just needs to be updated: lurume84/bling-viewer@499f393#diff-a55f5692772dd8c93564ed9c3e86ba99

@e-team-t
Copy link

e-team-t commented Aug 5, 2020

I changed line 248 of the api.py file to the following:

f"{blink.urls.base_url}/api/v5/accounts/{blink.account_id}/networks/{network}/cameras/{camera_id}/liveview"

and it is working fine, I am getting the immis link.

@fronzbot
Copy link
Owner

fronzbot commented Aug 5, 2020

Awesome! Feel free to make a pull request if you'd like. Otherwise I'll get that in some time this week

@cee-dee
Copy link

cee-dee commented Oct 25, 2020

Since the pull request was merged to dev I assumed that I could retrieve the liveview url via get_liveview. But I've trouble streaming it.

The server responds with
{ 'command_id': 91342095, 'join_available': True, 'join_state': 'available', 'server': 'immis://3.123.232.171:443/abcdef01234567890__IMDS_G8T11234513512B9?client_id=52265', 'duration': 300, 'continue_interval': 60, 'continue_warning': 10, 'submit_logs': True, 'new_command': True, 'media_id': None, 'options': { 'poor_connection': False } }

The method returns rstps//3.123.232.171443/abcdef01234567890__IMDS_G8T11234513512B9?client_id=52265, which is due to improper replacing of immis. But anyway, I cannot get players like vlc to stream the link rstp://3.123.232.171:443/abcdef01234567890__IMDS_G8T11234513512B9?client_id=52265.

Can anyone assist with this?

@fronzbot
Copy link
Owner

Full disclosure: I've never actually tested the method, just added it in because I saw the endpoint was there. Good catch on the game incorrect link formatting, I'll have to fix that!

Anyways, I'll try to test this today to see what my results are. It's possible the endpoint changed again and we're using a stale url.

@fronzbot
Copy link
Owner

Yeah I'm struggling to get this to work too. Not sure what the solution is

@cee-dee
Copy link

cee-dee commented Oct 26, 2020

Do you have a working livestream with another camera?
Can you see the network traffic on that protocol? Maybe it differs from the working version by some kind of custom header?

@fronzbot
Copy link
Owner

No I don't. Your hunch is probably a good one, but I'm ill-equipped to do any network sniffing, unfortunately

@cee-dee
Copy link

cee-dee commented Oct 29, 2020

Maybe there are ways to work work with an Android emulator to get insights in the traffic, see https://developer.android.com/studio/profile/network-profiler

But I haven't worked with that yet.

@foxm79
Copy link

foxm79 commented Jan 15, 2021

Are you all able to view a live stream from your blink mini or outdoor cams?

Hello @fronzbot!
Firstly, Thanks you soo much for this library.
I am able to download my images now.

For get_liveview() I think I fixed a small issue in the camera.py:

server_split[0] = "rtsps:"

server_split[0] = "rtsps:"
link = "".join(server_split)
to
server_split[0] = "rtsps"
link = ":".join(server_split)

With this I get the link as:
rtsps://52.34.34.83:443/NBl17cWGk61xIJKy__IMDS_G8T1900001642F9F?client_id=57905

But I am not able to view it.
Any help will go a long way!

@esistgut
Copy link

esistgut commented Jun 2, 2023

Did anyone figure this out? I see the "liveview" rest api returns 'join_available': True, 'join_state': 'available', among other things, maybe the cam has to be "joined" in order for the stream to work?

@KiraPC
Copy link

KiraPC commented Oct 10, 2023

Hello, any update on this?

@fronzbot
Copy link
Owner

Unfortunately, no. The protocol Blink uses appears to be proprietary and unless someone is able to crack it, anything with an immis link will be unviewable.

@simon2022
Copy link

any updates?

@MaUwJo
Copy link

MaUwJo commented Feb 18, 2024

any updates?

I downloaded the file "Blink Home Monitor_27.0_Apkpure.apk" and patched it with
apk-mitm --keep-tmp-dir Blink\ Home\ Monitor_27.0_Apkpure.apk
( https://github.com/shroudedcode/apk-mitm )strings libwalnut.so | grep immis
as I kept the tmp dir i'm able to navigate to it:
cd /tmp/apk-mitm-c08e4858c726d3cf7a351d94fe5ad834/decode/lib/x86_64
and do a strings libwalnut.so | grep immis
IMMIStreamSource can only operate on immis: URLs
immis
Receiving data after disconnect. immistreamsource._connectionState = %d
I think this is the library which is doing the imms stuff.
But unfortinuately my know how is not enought to analyze it deeper or to remove the ssl pining out of the library, so I could see unencrypted what's happening there.

All other calls to the API are now visible with PCAPDROID ( https://play.google.com/store/apps/details?id=com.emanuelef.remote_capture&hl=de&gl=US ) and the mitm binary which this tool can download.

Maybe there is someone out there who can analyze the details - I hope this helps.

@GiovanH
Copy link

GiovanH commented Jun 23, 2024

I'm using an old-but-working version of the iOS app, which communicates like this:

curl -i -s -k -X $'POST' \
    --data-binary $'{\"intent\":\"liveview\",\"motion_event_start_time\":\"\"}' \
    $'https://rest-u034.immedia-semi.com/api/v1/accounts/{account_id}/networks/{network_id}/owls/{camera_id}/liveview'

which the server responds to with:

{"command_id":1055540110,"join_available":true,"join_state":"available","server":"immis://18.216.15.175:443/[hash]__IMDS_[hash]?client_id=606199","duration":300,"extended_duration":5400,"continue_interval":60,"continue_warning":10,"polling_interval":15,"submit_logs":true,"new_command":true,"media_id":null,"options":{"poor_connection":false}}

It then takes that command int in the response and loops over GETing a url like

https://rest-u034.immedia-semi.com/network/{network_id}/command/{command}

which returns this interesting session-y object

{"complete":true,"status":0,"status_msg":"Command succeeded","status_code":908,"commands":[{"id":1055540110,"created_at":"2024-06-23T00:17:52+00:00","updated_at":"2024-06-23T00:18:53+00:00","deleted_at":null,"execute_time":"2024-06-23T00:17:52+00:00","command":"lv","state_stage":"vs","stage_rest":"2024-06-23T00:17:51+00:00","stage_cs_db":"2024-06-23T00:17:52+00:00","stage_cs_sent":"2024-06-23T00:17:52+00:00","stage_sm":"2024-06-23T00:17:52+00:00","stage_dev":null,"stage_is":null,"stage_lv":null,"stage_vs":"2024-06-23T00:17:52+00:00","state_condition":"done","sm_ack":1,"lfr_ack":null,"sequence":172,"attempts":0,"transaction":"[hash]","player_transaction":"k-vUceCm9z7vMFqY","server":"immis://18.216.15.175:443/[hash]","duration":61,"by_whom":"[device name] - 6.26.0 (2305082009) #a328e77a4-mod - liveview","diagnostic":false,"debug":"","opts_1":0,"target":"owl","target_id":xx,"trace_parent":null,"sync_module_id":0,"parent_command_id":null,"camera_id":null,"siren_id":null,"firmware_id":null,"network_id":xx,"account_id":xx}],"media_id":null}

Note the transaction value is the hash from the imms url.

@jakecrowley
Copy link

I was able to make some progress in figuring out the immis protocol by using frida to hook the mbedtls_x509_crt_verify_with_profile function exported from the libwalnut.so native library so I could bypass their SSL pinning and proxy the unencrypted the immis stream. I uploaded a script that sends the proper connection header to the TCP socket and pipes the output to ffplay, and is able to get a livestream to play.

fyi this is an extremely early proof-of-concept, and ffplay spits out a bunch of DecodeFrame failed errors which I assume are other blink proprietary packets sent alongside the video stream, which haven't been figured out yet.

https://gist.github.com/jakecrowley/a874e99cc06431877d4f933441cc8353

@amattu2
Copy link

amattu2 commented Nov 9, 2024

I was able to make some progress in figuring out the immis protocol by using frida to hook the mbedtls_x509_crt_verify_with_profile function exported from the libwalnut.so native library so I could bypass their SSL pinning and proxy the unencrypted the immis stream. I uploaded a script that sends the proper connection header to the TCP socket and pipes the output to ffplay, and is able to get a livestream to play.

fyi this is an extremely early proof-of-concept, and ffplay spits out a bunch of DecodeFrame failed errors which I assume are other blink proprietary packets sent alongside the video stream, which haven't been figured out yet.

https://gist.github.com/jakecrowley/a874e99cc06431877d4f933441cc8353

Wow, incredible work on this! I just verified that it seems to work for the Blink "owl" camera (aka Blink Mini) and also the "superior" (aka Floodlights).

Worth noting, the following line was giving an error for missing the positional argument byteorder:

    conn_header = bytes([
        0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + list(client_id.to_bytes(4)) + [0x01, 0x08, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x10] + list(bytes(conn_id, 'ASCII')) + [0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00,
    ])

I replaced list(client_id.to_bytes(4)) with list(client_id.to_bytes(4, "big")) and that seems to work now.

BTW, the API subdomain changes per region, it might be worth annotating that.

This is a huge step towards once-again enabling live-view via third party tooling.

@jakecrowley
Copy link

jakecrowley commented Nov 13, 2024

Update, I majorly streamlined the process of proxying the immis stream, and packaged it into a repo so that others who are interested can also look into this protocol. I only own the Blink Mini, but I know some devices have pan/tilt and other functionality that I think might be sent as special packets through the immi stream, if you want you can send pcaps (maybe cover the camera if you're worried about privacy), otherwise you can take a crack at picking apart the protocol yourself.

https://github.com/jakecrowley/blink-immis-proxy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help-wanted Assistance required due to lack of resources for testing or complexity
Projects
None yet
Development

No branches or pull requests