Introduction

For those of you who are new to doorbot, here is the description taken from Wikipedia :

”¬†Doorbot is a doorbell replacement, created by Edison Junior in 2012 that includes an infrared camera, and wi-fi connectivity. When the doorbell is pressed, the app begins a VOIP video call to connected smartphones, so that the owner can see and speak with whoever is at the door.

The Doorbot app has integrated Lockitron support, so that the door may also be remotely unlocked when the doorbell is rung.¬†”

Lets be clear : Doorbot is an amazing initiative. I had been dreaming of such a device/system for years and even built a couple of prototypes but nothing as clean, good looking or easy to install.
It is however still in its infancy and its software is a bit clunky at times.
Furthermore, it currently does not integrate with other systems.
All of these concerns have been acknowledged by its makers and APIs/SDKs are soon to be on their way.

While we wait for new and exciting features from Edison Junior, I thought I would tinker a bit with the device itself and see how I might make it do more than it currently does.

My initial ideas are to implement 3rd party notification (such as SMS or Instant Messaging), VoIP/SIP integration (to a certain degree. At least try to get the Doorbot to ring an IP Phone in some way) and possibly a desktop client.

For now, I will just share my findings and hopefully get the ball rolling for all the other Doorbot fans/tinkers out there.

 

First pass at communications reversing

First order of business, lets take a look at what our DoorBot does upon pressing the button.

After finding the IP address of the DoorBot on my DHCP server (hereafter 192.168.1.157), a bit of packet capture will probably give us a better understanding of what is happening and how we can work with it.

Screenshot_2

Clearly there's a couple of things happening here.
It looks like 4 different kinds of traffic are at play :

DoorBot <- DNS Query -> DNS Server (DNS)
DoorBot <- HTTP -> Server A (Control)
DoorBot <- HTTPs -> Server B (Stream Negotiation)
DoorBot — UDP -> Server B (Stream Content)

An quick read seems to show that the exchange is relatively straight forward.
In the first phase, DoorBot makes a DNS query for fw.mydoorbot.com and then sends and HTTP POST to a restfull service URL there (/doorbots_api/dings).

 

POST /doorbots_api/dings HTTP/1.1
Host: fw.mydoorbot.com
Authorization: Basic ……………………………………==
Content-Length: 0

Note that the the POST also contains a Basic HTTP Authentication Header. This Header is always the same for a given DoorBot and identifies that specific DoorBot on the server side.
The service responds with a JSON payload that seems to specify the addresses and specifications required to initial an RTSP media stream.

 

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
Date: Sat, 09 Aug 2014 03:18:42 GMT
ETag: "................................"
Server: nginx/1.4.6 (Ubuntu)
Set-Cookie: request_method=POST; path=/
Status: 200 OK
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: .......-....-....-....-..........
X-Runtime: 0.047823
X-UA-Compatible: chrome=1
X-XSS-Protection: 1; mode=block
Content-Length: 276
Connection: keep-alive

{"ding":{"id":1014761,"state":"ringing","client_stream_ip":"54.204.43.49","client_stream_port":"18308","device_stream_url":"rtsp://162.243.1.146:443/d/10147611407554322","device_stream_ip":"162.243.1.146","device_stream_port":"443","device_stream_path":"d/10147611407554322"}}

Here's the JSON part in a slightly more readable form :

{
  "ding": {
    "id": 1014761,
    "state": "ringing",
    "client_stream_ip": "54.204.43.49",
    "client_stream_port": "18308",
    "device_stream_url": "rtsp://162.243.1.146:443/d/10147611407554322",
    "device_stream_ip": "162.243.1.146",
    "device_stream_port": "443",
    "device_stream_path": "d/10147611407554322"
  }
}

Note that the media stream server addresses are in IP form, no further DNS requests are required.

The stream "path" seems to be randomly generated at each ring (which makes sense).
Also note the "id" field. This seems to be a unique identifier specific to this "DING" session. It is reused further down.

DoorBot then contacts the stream server and announces its RTSP stream.
 

ANNOUNCE rtsp://162.243.1.146:443/d/10147611407554322 RTSP/1.0
CSeq: 1
Content-Language: en-US
Content-Length: 594
Content-Type: application/sdp

v=0
o=- 0 0 IN IP4 192.168.1.157
s=/d/10147611407554322
c=IN IP4 162.243.1.146
t=0 0
a=control:*
a=range:npt=0.000000-
a=tool:Flussonic http://www.getdoorbot.com/
a=x-qt-text-nam:Doorbot streaming
a=x-qt-text-inf:h264
a=type:broadcast
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=cliprect:0,0,640,480
a=framesize:96 640-480
a=x-dimensions:640,480
a=fmtp:96 packetization-mode=1;profile-level-id=42E01E;sprop-parameter-sets=............,...........
a=control:streamid=0
b=AS:200
m=audio 0 RTP/AVP 0
b=AS:128
a=rtpmap:0 PCMU/8000/1
a=fmtp:0
a=control:streamid=1

What's interesting to note here is that the announcement carries a standard SDP segment descriting 2 streams :
An H.264 video stream, 640×480 (Stream 0)
A PCM U-law 8k Audio stream (Stream 1)
It is also interesting to note (maybe for future reference) that the ANNOUNCE method is not implemented in a lot of media streaming servers. Its only part of the 1.0 RTSP protocol spec and has been removed in 2.0.

The server responds with an acknowledgment :

RTSP/1.0 200 OK
Server: Flussonic (http://www.flussonic.com/) 4.1.30
Cseq: 1

Hello Flussonic :-) A very well known Media Streaming Server out there.
Next, our DoorBot sets up its 2 media streams and the Flussonice server acknowledges both.

DoorBot says :

SETUP rtsp://162.243.1.146:443/d/10147611407554322/streamid=0 RTSP/1.0
CSeq: 2
Transport: RTP/AVP/UDP;unicast;client_port=51504-51505;mode=record

Media Server says :

RTSP/1.0 200 OK
Server: Flussonic (http://www.flussonic.com/) 4.1.30
Session: 9b9ba299-fd91-4ece-ad5e-a6e4dca0cdb9
Cseq: 2
Transport: RTP/AVP;unicast;client_port=51504-51505;server_port=14688-14689;mode=receive

DoorBot says :

SETUP rtsp://162.243.1.146:443/d/10147611407554322/streamid=1 RTSP/1.0
CSeq: 3
Session: 9
Transport: RTP/AVP/UDP;unicast;client_port=51506-51507;mode=record

Media Server Says :

RTSP/1.0 200 OK
Server: Flussonic (http://www.flussonic.com/) 4.1.30
Session: 9b9ba299-fd91-4ece-ad5e-a6e4dca0cdb9
Cseq: 3
Transport: RTP/AVP;unicast;client_port=51506-51507;server_port=18260-18261;mode=receive


During the exchange, the server also responds with the ports on which it is expecting the 2 streams to be sent. This will be used a bit further when the streams start.
Finally, the DoorBot tells the media server to start recording the stream for rebroadcasting (which our phones/tablets will join in order to view the stream)

DoorBot Says :

RECORD rtsp://162.243.1.146:443/d/10147611407554322 RTSP/1.0
CSeq: 4
Session: 9
Range: npt=0.000-

Media Server Says :

RTSP/1.0 200 OK
Server: Flussonic (http://www.flussonic.com/) 4.1.30
Session: 9b9ba299-fd91-4ece-ad5e-a6e4dca0cdb9
Cseq: 4

 

At this point the streaming starts : DoorBot starts sending its audio and video to the specified ports via UDP.
In the mean time, DoorBot periodically (every 500ms) contacts the control server on that REST service to see what the status us on our current "DING" session

DoorBot says :

GET /doorbots_api/dings/1014761 HTTP/1.1
Host: fw.mydoorbot.com
Authorization: Basic .................................................==
Content-Length: 0

Control Server says :

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
Date: Sat, 09 Aug 2014 03:18:43 GMT
ETag: "0e204e6dffc917b38c0db2a10fa7777b"
Server: nginx/1.4.6 (Ubuntu)
Set-Cookie: request_method=GET; path=/
Status: 200 OK
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: a7c8669c-c7e9-4f31-8f02-0eb1cb77a06f
X-Runtime: 0.013639
X-UA-Compatible: chrome=1
X-XSS-Protection: 1; mode=block
Content-Length: 28
Connection: keep-alive

{"ding":{"state":"ringing"}}

 

As before, JSON encoded response stating our session is ringing. Since I havent answered the call on any of my devices, this makes perfect sense.
This same exchange (same request, same response) continues to happen every 500ms until one of the devices picks up the call, at which point the "state" parameter from the server changes to "connected"

 

DoorBot says :
GET /doorbots_api/dings/1014761 HTTP/1.1
Host: fw.mydoorbot.com
Authorization: Basic .....................................==
Content-Length: 0

Control Server says :

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
Date: Sat, 09 Aug 2014 03:18:48 GMT
ETag: "a5fccc27b4e751adb5564f90164f426f"
Server: nginx/1.4.6 (Ubuntu)
Set-Cookie: request_method=GET; path=/
Status: 200 OK
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: 6662b691-38df-437b-8cde-375f7c4ce6fa
X-Runtime: 0.014820
X-UA-Compatible: chrome=1
X-XSS-Protection: 1; mode=block
Content-Length: 30
Connection: keep-alive

{"ding":{"state":"connected"}}

After that, the server will continue to reply that the session is "connected" until the call is hung-up by the remote device.

DoorBot says :

GET /doorbots_api/dings/1014761 HTTP/1.1
Host: fw.mydoorbot.com
Authorization: Basic .............................................==
Content-Length: 0

Control Server says :

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
Date: Sat, 09 Aug 2014 03:19:24 GMT
ETag: "f67ae60df24dfa332239de61f49ca641"
Server: nginx/1.4.6 (Ubuntu)
Set-Cookie: request_method=GET; path=/
Status: 200 OK
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: e822ff75-fc23-48ad-b9c3-370584801cfc
X-Runtime: 0.012025
X-UA-Compatible: chrome=1
X-XSS-Protection: 1; mode=block
Content-Length: 30
Connection: keep-alive

{"ding":{"state":"completed"}}

At this point, DoorBot hangs up its end of the call by tearing down the session with the Media Server :

DoorBot says :

TEARDOWN rtsp://162.243.1.146:443/d/10147611407554322 RTSP/1.0
CSeq: 5
Session: 9

Media Server says

RTSP/1.0 200 OK
Server: Flussonic (http://www.flussonic.com/) 4.1.30
Session: 9b9ba299-fd91-4ece-ad5e-a6e4dca0cdb9
Cseq: 5

 

DoorBot then sends a final message to the control server with its current status, battery status, software versions etc.
(Interestingly enough, this part is from-encoded instead of JSON)

DooBot says :

POST /doorbots_api/status_reports HTTP/1.1
Host: fw.mydoorbot.com
Authorization: Basic ........................................==
Content-Length: 743
Content-Type: application/x-www-form-urlencoded

status_report[status][battery_counts]=901&status_report[status][battery_voltage]=3441&status_report[status][battery_state]=2&status_report[status][battery_percentage]=4&status_report[status][ext_connection]=0&status_report[firmware_versions][app]=2.18E&status_report[firmware_versions][wlan]=2.5.1.17&status_report[firmware_versions][imager]=0&status_report[firmware_versions][fs]=1.0.0&status_report[current_settings][time]=0&status_report[current_settings][utc_offset]=0&status_report[current_settings][ledNightEn]=1&status_report[current_settings][ap_keepalive]=50&status_report[current_settings][update_check_time]=0&status_report[current_settings][update_check_day]=127&status_report[current_settings][mfr_mode]=1&status_report[context]=1

Control Server says :

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
Date: Sat, 09 Aug 2014 03:19:24 GMT
ETag: "7215ee9c7d9dc229d2921a40e899ec5f"
Server: nginx/1.4.6 (Ubuntu)
Set-Cookie: request_method=POST; path=/
Status: 200 OK
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: 3092efce-6cce-48db-b7bb-b38f1c0776cb
X-Runtime: 0.047018
X-UA-Compatible: chrome=1
X-XSS-Protection: 1; mode=block
Content-Length: 1
Connection: keep-alive

Initial Conclusions

This first pass at looking at the communications around the DoorBot is obviously incomplete. We have only looked at the DoorBot to Server communications but havent really touched the Server to Device/Receiver communications. This will be the subject of another tinkering session (when time will allow).

Still, we can already take a couple of educated guesses and conclusions based on what we've found so far.

The control protocol in use uses standard HTTP methods and is relatively simple. Furthermore, it is unencrypted which will make it easier to work with.
The media part is textbook RTSP 1.0. This is also easy to work with.

I think future versions version of the DoorBot firmware might benefit from abandonning this approach and implementing SIP instead.
The hardware is clearly able to generate standard IP Telephony streams (H.264 and PCMU) … event the RTSP control frames contain SDPs that could just as well be using in a SIP negociation.
Even the status reporting could be implemeted in SIP using all sorts of trickery : Presence messaging, Out-of-Band messaging… you name it.
Having a standard SIP implementation would also make it easier to integrate with open-source Soft PBX solutions like Asterisk.
It could be an "option" somewhere on the DoorBot site where you could choose which version of the firmware you'd like to run.

Talking of firmware, wouldnt it be awesome if it were open sourced ? or partially published in order for tinkers like us to contribute and make the product even better ?

Still, as it is, we have plenty of things to play with.
One little experiment I just ran was to play man-in-the-middle on the Control side of the DoorBot protocol.

Here's a quick tutorial :

Requirements : 
Apache (with mod_rewrite enabled) + PHP (with CURL)
A DNS Server you control (dnsmasq will do fine)

Step 1 – Manually configure the DoorBot's IP  and point the DNS setting to your own DNS server

Step 2 – Configure you DNS server to relay all requests but set fw.mydoorbot.com to the IP address of your Apache server. Make sure the server itself doesnt use that DNS server.

Step 3 – Configure a virtual-host on your web server for fw.mydoorbot.com (I've set it for both HTTP and HTTPS with a self signed certificate but it looks HTTPS isnt used for now)

Step 4 – In your document root, add the following files :

index.php

<?php
        $payload=file_get_contents('php://input');
        $url=$_SERVER['REQUEST_URI'];
        if($_SERVER['SERVER_PORT']==443)
                $host="https://fw.mydoorbot.com";
        else
                $host="http://fw.mydoorbot.com";

        file_put_contents('comm.log',"\n\n### IN : $url###\n".$payload,FILE_APPEND);

        $ch = curl_init($host.$url);
        if($_SERVER['REQUEST_METHOD']=='POST')
        {
                curl_setopt ($ch, CURLOPT_POST, 1);
                curl_setopt ($ch, CURLOPT_POSTFIELDS, $payload);
        }
        if(!empty($_SERVER['PHP_AUTH_USER']))
        {
                $username=$_SERVER['PHP_AUTH_USER'];
                $password=$_SERVER['PHP_AUTH_PW'];
                curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
                curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
        }
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_VERBOSE, 1);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        $response=curl_exec ($ch);
        list($header, $body) = explode("\r\n\r\n", $response, 2);
        curl_close ($ch);
        file_put_contents('comm.log',"\n\n### HEADERS ###\n".$header,FILE_APPEND);
        file_put_contents('comm.log',"\n\n### OUT ###\n".$body,FILE_APPEND);
        foreach(explode("\n",$header) as $h)
                header($h);
        echo $body;

.htaccess

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

 

If everything goes well, all the control messages from your DoorBot will relay via your script (and for now logged in a comm.log file for this example).
Once you've got that working, here's a fun tricks :

Tail the comm.log file and catch the "device_stream_url" parameter from the first message back from the control server.
Copy the URL and open it in VLC
Boom ! You'll see and hear your DoorBot's streams while its ringing or connected.

A couple of ideas based on that experiment :
- Implement a local message broadcast that will be cought by a desktop up which will popup the video when someone rings the door.
- Have the script generate a "call file" for Asterisk that rings a few phones and starts app_rtsp with the stream URL.
- Implement the rest of the control protocol instead of relaying it and use a local gstreamer or flussonic server to remove lag

 

I will continue tinkering with my DoorBot on my spare time.

 

 

Second Pass and Comm Reversing

Today I thought I'd take a moment to see what happens on the other end of the stick:

The communications between the mobile app (Android in this case) and the servers.

This time, things are tiny bit trickier.

The application talks to REST URLs over HTTPs on a host named api.mydoorbot.com In order to sniff that out, we're going to have to play man-in-the-middle
After some tinkering, I found that the best solution in this case would be to generate a CA certificate and sign my own certificate for api.mydoorbot.com with it.
A greate tutorial on creating your CA and self-signed certificate can be found here : http://www.debian-administration.org/article/284/Creating_and_Using_a_self_signed__SSL_Certificates_in_debian

If you're using Android, you'll also want to convert the certificate to the Android certificate file format and add it to your phone/tablet under /system/etc/security/cacerts/
More information about that can be found at : http://wiki.cacert.org/FAQ/ImportRootCert#CAcert_system_trusted_certificates_.28without_lockscreen.29

With that in place, I was able to relay/proxy the HTTPs requests from the Android app and take a peek at what happends on that end.
Here's an extract :

# Result Protocol Host URL Body Caching Content-Type
48 200 HTTPS api.mydoorbot.com /clients_api/doorbots?auth_token=…. 554 max-age=0, private, must-revalidate application/json; charset=utf-8
49 200 HTTPS api.mydoorbot.com /clients_api/doorbots?auth_token=…. 554 max-age=0, private, must-revalidate application/json; charset=utf-8
50 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 234 max-age=0, private, must-revalidate application/json; charset=utf-8
51 200 HTTPS api.mydoorbot.com /clients_api/doorbots?auth_token=…. 554 max-age=0, private, must-revalidate application/json; charset=utf-8
52 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 234 max-age=0, private, must-revalidate application/json; charset=utf-8
53 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 234 max-age=0, private, must-revalidate application/json; charset=utf-8
54 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 234 max-age=0, private, must-revalidate application/json; charset=utf-8
55 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 234 max-age=0, private, must-revalidate application/json; charset=utf-8
56 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431/keep-alive?auth_token=…. 236 max-age=0, private, must-revalidate application/json; charset=utf-8
57 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 236 max-age=0, private, must-revalidate application/json; charset=utf-8
58 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 236 max-age=0, private, must-revalidate application/json; charset=utf-8
59 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431/keep-alive?auth_token=…. 236 max-age=0, private, must-revalidate application/json; charset=utf-8
60 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 236 max-age=0, private, must-revalidate application/json; charset=utf-8
61 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 236 max-age=0, private, must-revalidate application/json; charset=utf-8
62 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 236 max-age=0, private, must-revalidate application/json; charset=utf-8
63 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431/keep-alive?auth_token=…. 236 max-age=0, private, must-revalidate application/json; charset=utf-8
64 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431/hang-up?auth_token=…. 236 max-age=0, private, must-revalidate application/json; charset=utf-8
65 200 HTTPS api.mydoorbot.com /clients_api/doorbots?auth_token=…. 554 max-age=0, private, must-revalidate application/json; charset=utf-8
66 200 HTTPS api.mydoorbot.com /clients_api/dings/1026431?auth_token=…. 236 max-age=0, private, must-revalidate application/json; charset=utf-8

As you can see, its pretty similar to what the DoorBot actually does. Its contacting a "Control server" in order to get information about the available DoorBots for that account and then calls the "dings" service when a call comes in.
I suspect that what triggers the "dings" calls is probably some sort of Android notification service but I havent gone that far in the packets just yet. I'll dig around some more later.
Note that an auth_token is passed at every call. I believe it to be some hash combination from the login and password pair for your DoorBot account. More digging to be done on that front too.

So what does the communcation actually look like ?
Well, its pretty similar to what we've seen previously with DoorBot. Here's the first request :

Phone says :

GET https://api.mydoorbot.com/clients_api/doorbots?auth_token=xxxxxxxxxxxxxxxxxxxxx HTTP/1.1
Host: api.mydoorbot.com
Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)

Control Server says :

HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 11 Aug 2014 23:23:22 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Set-Cookie: __cfduid=……; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.mydoorbot.com; HttpOnly
Status: 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Ua-Compatible: chrome=1
Etag: '9d105d2ccabb92352dceddb320458102'
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: request_method=GET; path=/
Set-Cookie: _doorbot-web_session=….; path=/; HttpOnly
X-Request-Id: a065c1bd-0f87-44d4-8f2b-ebd7a75bdfdd
X-Runtime: 0.090088
Via: 1.1 vegur
CF-RAY: 15882e3987be0ed3-EWR
Content-Length: 554

{'doorbots':[{'id':8308,'description':'Front Door','time_zone':'Eastern Time (US \u0026 Canada)','subscribed':true,'battery_life':100,'owner':{'id':5694,'email':'........','created_at':'2013-12-28T22:34:42.565Z','updated_at':'2014-08-11T23:14:09.379Z'}},{'id':4016,'description':'Side Door','time_zone':'Eastern Time (US \u0026 Canada)','subscribed':true,'battery_life':100,'owner':{'id':5694,'email':'.......','created_at':'2013-12-28T22:34:42.565Z','updated_at':'2014-08-11T23:14:09.379Z'}}],’authorized_doorbots’:[]}

 

This is pretty streight forward ; The app asks what doorbots are available for that account and the server answers with some basic information. Namely 2 doorbots :
- Front Door : Battery Live 100% etc…
- Side Door : Battery Life 100% etc..

When a call comes in, the app start poking the "dings" service periodically.

App says :

GET https://api.mydoorbot.com/clients_api/dings/1026431?auth_token=xxxxxxxxxxxxxxxxxxxxx HTTP/1.1

Server says :

{'id':1026431,'state':'ringing','protocol':'rtsp','doorbot_id':8308,'doorbot_description':'Front Door','client_stream_ip':'54.204.43.49','client_stream_port':'18308','device_stream_url':'rtsp://107.170.21.117:443/d/10264311407799532'}
 

 


Note that the server response contains all the necessary data to establish the "sort-of" 2 way communication : It has the rtsp stream URL and the client_stream info.
I'm not too sure about what the client_stream info looks like. I did notice however that the port number seems to be the ID of the doorbot incremented by 10000.
That stream is TCP for some reason… I'm assuming it is the stream used to send the audio from the device to the DoorBot's speaker but I still havent found what format or encapsulation its in.
The fact that its in TCP is rather odd since media is usually in UDP.


In order to ANSWER the call, the app posts to that same server but with an added parameter/path in the URL string (keep-alive):

App Says :

POST https://api.mydoorbot.com/clients_api/dings/1026431/keep-alive?auth_token=xxxxxxxxxxxxxxxxxxxxx HTTP/1.1
Accept: application/json
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.4.4; SGH-I337M Build/KTU84P)
Host: api.mydoorbot.com
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

Server Says :

HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 11 Aug 2014 23:25:32 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Set-Cookie: __cfduid=……; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.mydoorbot.com; HttpOnly
Status: 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Ua-Compatible: chrome=1
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: request_method=POST; path=/
Set-Cookie: _doorbot-web_session=…….; path=/; HttpOnly
X-Request-Id: fd34f53c-ef2d-418e-a200-6d10a991d42b
X-Runtime: 0.076135
Via: 1.1 vegur
CF-RAY: 15883163027c0ed3-EWR
Content-Length: 236

{'id':1026431,'state':'connected','protocol':'rtsp','doorbot_id':8308,'doorbot_description':'Front Door','client_stream_ip':'54.204.43.49','client_stream_port':'18308','device_stream_url':'rtsp://107.170.21.117:443/d/10264311407799532'}

 

 

It seems that the Keep-Alive URL is being called every time we also press the "Push-To-Talk" button but I may be wrong on that one.

In order to hang-up the call, the app does another post in a similar fashion :

App says :

POST https://api.mydoorbot.com/clients_api/dings/1026431/hang-up?auth_token=xxxxxxxxxxxxxxxxxxxxx HTTP/1.1
Accept: application/json
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.4.4; SGH-I337M Build/KTU84P)
Host: api.mydoorbot.com
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

Server says :

HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 11 Aug 2014 23:25:43 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Set-Cookie: __cfduid=db271569a8eb11d948270b4a2468d40e91407799543073; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.mydoorbot.com; HttpOnly
Status: 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Ua-Compatible: chrome=1
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: request_method=POST; path=/
Set-Cookie: _doorbot-web_session=eFROTWRJRHI4U092UlduY240Z1ByWEUwQTJkTFFNc3NUbmx0ZXBTdHN4L25sYmlvTk5qTnpJdE9pNFJ5YzZzK09YYmtmOEQzY2tpVHhFMkRhM3lLZ3ljT3hMQzdXT0VuYTMrV241YVQxU0MrdEwzUW5sYmlNdGVuV3JqT2tHV2l6T3NwZnBpb0s0aXpUY3N4SkhIS0lBPT0tLW9EMHJGOWFTMFVRZDNua0FMTVFmdXc9PQ%3D%3D–2e63617b8d7603f60c6f0f09b1b0ae3ae2f85179; path=/; HttpOnly
X-Request-Id: d342a408-4838-40ae-9131-25c28baf0892
X-Runtime: 0.031886
Via: 1.1 vegur
CF-RAY: 158831a832c00ed3-EWR
Content-Length: 236

{'id':1026431,'state':'completed','protocol':'rtsp','doorbot_id':8308,'doorbot_description':'Front Door','client_stream_ip':'54.204.43.49','client_stream_port':'18308','device_stream_url':'rtsp://107.170.21.117:443/d/10264311407799532'}

 

 

After the call has been hung up, the app makes 2 final calls :
One to the /doorbots service to update its status of the available doorbots on the account.
One to the "dings" service with the same ding ID, probably to confirm that it is truely completed.

 

Conclusions on second pass

The format used by the app to communicate with the DoorBot servers is very similar to the one used by the DoorBot itself with the slight difference that it uses SSL encryption.
The JSON payloads are pretty simple to understand.

With those pieces in hand, we could almost start looking at writing a desktop application/client for doorbot.
The only pieces missing for that are :
- What is the auth_token format ? What is it based on ?
- How do we get notified of an incoming "Ding"… it is handled by the mobile OS's notification API ?
- What is the format in which the app sends out its audio back to DoorBot ?

The first part we can bypass relatively easily since apparently the token doesnt change from one session to another. We can simply steal the one from our captured sessions and it will work just fine.
The second part can be worked around… since we can already intercept the outgoing DING notification from the DoorBot itself (using a simple trick like the script I pasted in my first conclusions), we could create our own notification signaling locally.
The rest we can easily implement in any language. We would be able to view ringing calls, answer calls and hang them up. We just wouldnt be able to send audio just yet (at least until we figure out what that audio protocol is)

We almost have all the necessary pieces to actually replace the DoorBot servers as well (to a certain extent).
The protocols can be implemented using PHP. We can hijack the DNS requests and forward fw.mydoorbot.com and api.mydoorbot.com to our own servers, and we can install our own media server. I've been looking at Flussonic but it requires some license in order to work. I think I'll try Live555, GStreamer or even Darwin to see if they might work as a drop-in replacement.

More to come on that front when I have a bit more time to tinker. 

Until then, happy hacking :-)

IP address and server changes

Looks like our friends at Edison Junior are playing around with servers these days.
I’ve tried a few times to offer my help but have been faced with the ever-usual no response.
That being said, my doorbot now seems to talk to doorbot-production.herokuapp.com instead of fw.mydoorbot.com… at least for its dings.
And with that, my doorbots simply no longer work. I get the ring to go to my phone ever once in a while but I almost never get any audio or video and when I do, its almost always garbled or simply black/blank.
I hope this is just a transition thing while they play with their servers… I’m a bit worried of the current state of affairs.
As soon as I’ve had time to analyse the packets captured today I’ll post another quick update with my findinds.

Cheers all.

Step aside DoorBot, here comes Ring ?

As many of you may have gatherd from Jamie’s email today, the DoorBot team seems to have been hard at work in developing DoorBot’s next generation hardware.
The device call “Ring” was announced today in an email sent to all DoorBot owners.
The new device’s website is located at https://ring.com/

On the plus side, the guys at Edison Junior seem to really have been hard at work in implementing the features requested by DoorBot uses’s feedback.
On the downside, it seems that all of those efforts were put into working on a new device and very little of it was put into trying to help existing DoorBot users.

I have no additional comments for now and the above statements are just my initial impression.
I have reached out to Jamie Siminoff (CEO) about my concerns and hope to hear back from him.