惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
O
OpenAI News
Forbes - Security
Forbes - Security
W
WeLiveSecurity
Engineering at Meta
Engineering at Meta
Stack Overflow Blog
Stack Overflow Blog
P
Privacy & Cybersecurity Law Blog
The Register - Security
The Register - Security
T
Tor Project blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
S
Secure Thoughts
D
DataBreaches.Net
Vercel News
Vercel News
D
Docker
T
The Blog of Author Tim Ferriss
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
M
MIT News - Artificial intelligence
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
L
LangChain Blog
博客园_首页
S
Schneier on Security
宝玉的分享
宝玉的分享
Project Zero
Project Zero
V
Visual Studio Blog
Attack and Defense Labs
Attack and Defense Labs
量子位
P
Proofpoint News Feed
The GitHub Blog
The GitHub Blog
B
Blog
V2EX - 技术
V2EX - 技术
T
Troy Hunt's Blog
N
Netflix TechBlog - Medium
H
Hacker News: Front Page
Cloudbric
Cloudbric
云风的 BLOG
云风的 BLOG
Latest news
Latest news
P
Proofpoint News Feed
Help Net Security
Help Net Security
Schneier on Security
Schneier on Security
H
Heimdal Security Blog
Hacker News: Ask HN
Hacker News: Ask HN
有赞技术团队
有赞技术团队
B
Blog RSS Feed
Last Week in AI
Last Week in AI
C
Cyber Attacks, Cyber Crime and Cyber Security
I
Intezer
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Webroot Blog
Webroot Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Microsoft Security Blog
Microsoft Security Blog

夜行人

回家路上 第一期的直播演示项目 震动检测器 正能量 在线参观CodeLab Neverland 发布 CodeLab Adapter 3.3.1 DynamicTable 之 纸糊方向盘 CodeLab DynamicTable: 一个可实施的技术方案 CodeLab Insight 发布 Alpha 版 情人节 Home Assistant 周报 && IoT 周报 (02) Joplin: 关注隐私的 Evernote 开源替代软件 浏览器的未来与 Web 传感器 Home Assistant 周报 && IoT 周报 (01) 百宝箱(01) 论自由 介绍 WebThings Home Assistant 周报 && iot 周报 (00) 百宝箱(00) 毛姆读书心得 传世之作 周末徒步 CodeLab Adapter ❤️ Jupyter/Python 航班 躲雨 夏令营途中 [译]思想--作为一种技术 The future of coding 美国之行 三门问题的程序模拟 从Python转向Pharo https://blog.just4fun.site/post/iot/iot-open-source-projects/ Python异步编程笔记 https://blog.just4fun.site/post/iot/iot-open-source-hardware-community/ 万物积木化开发者社区 CodeLab ❤️ Blender Scratch3技术分析之云变量 API(第7篇) [译]对管道(Pipes)的偏爱 [译]提出正确的问题比得到正确答案更重要 蓝牙设备与Scratch3.0 创建你的第一个Scratch3.0 Extension Scratch3技术分析之项目内部数据(第6篇) Scratch3技术分析之社区 API(第5篇) Scratch3技术分析之User API(第4篇) Scratch3技术分析之项目主页API(第3篇) Scratch3技术分析之静态资源API(第2篇) Scratch3.0、micro:bit与Windows7 https://blog.just4fun.site/post/iot/zerynth-vs-micropython/ 核聚变、方所与半宅空间 可视化编程为何是个糟糕的主意 codelab.club周末聚会 关于codelab.club '下一件大事'是一个房间 Hungry Robot - Eat everything 编程作为一种思考方式 今日简史 史蒂夫·乔布斯传 罗素自选文集 https://blog.just4fun.site/post/edx/tianjin-scratch-ai/ https://blog.just4fun.site/post/edx/richie-cms-openedx/ 徒步武功山 WebUSB与micro:bit 积木化编程与3D场景 夜宿武功山顶 scratch3-adapter接入优必选Alpha系列机器人 https://blog.just4fun.site/post/edx/video-migration-note/ scratch3-adapter重构笔记 https://blog.just4fun.site/post/edx/edx-community-members/ 两种硬件编程风格的比较 使用micro:bit自制PPT翻页笔 柏拉图对话集 scratch3.0 + micro:bit 七月电影放映计划 非营利组织的管理 Screenly--用树莓派让任何屏幕变为可编程的数字标牌 以最佳实践开始你的Django项目 micro:bit与事件驱动 为Scratch3.0设计的插件系统(上篇) OCR应用一例 近两年读过的一些好书 blockly开发之使用python驱动浏览器中的turtle(2) 牛顿新传 文学理论入门 逻辑的引擎 人生的意义 blockly开发之生成并运行js代码(1) blockly开发之hello world(0) micro:bit使用笔记 神器之Termux https://blog.just4fun.site/post/iot/micropython-notes/ Cozmo what is this Scratch的前世今生 下段旅程 我行在远方 爆裂 途中杂记 https://blog.just4fun.site/post/edx/open-edx-startup/ cozmo系列之入门 - 有性格且可编程的机器人 PaperWeekly开发笔记 创业二三事
Home Assistant Cloud 分析
种瓜 · 2019-06-27 · via 夜行人

文章目录

前言

Home Assistant 折腾笔记一文中,我们曾提及Home Assistant Cloud

Home Assistant Cloud是什么

Home Assistant Cloud提供安全的远程连接,允许你远程控制设备(在你外出的时候),也允许Amazon Alexa and Google Assistant控制Home Assistant实例.

目前该服务由Home Assistant的合作伙伴Nabu Casa, Inc提供。Nabu Casa, Inc由Home Assistant 和 Hass.io的联合创始人创建。


Home Assistant Cloud目前由Nabu Casa, Inc提供, nabucasa client是开源的:nabucasa(我当前本地安装的版本是0.14),对于hass_nabucasa的交互逻辑,可以从测试代码中学习:test_cloud_api.py

但在国内使用,延迟比较严重,哪天被墙了也难说。本文试图对Home Assistant Cloud 进行分析,为今后自行构建Home Assistant Cloud server提供参考,这个工作颇似我们此前对Scratch做的分析

思路

为了理解Home Assistant Cloud的工作原理,我们将从前端开始,观察通信过程,之后跟踪到Home Assistant后端源码里(nabucasa组件是核心部分),最后对Home Assistant Cloud server进行推断。

前端分析(通信过程)

首先打开Home Assistant Cloud: http://127.0.0.1:8123/config/cloud/account

我们从登陆开始:

登陆

POST: http://127.0.0.1:8123/api/cloud/login

Request Payload: {"email":"EMAIL","password":"PASSWORD"}

Response: {"success": true}

登陆完成之后, websocket发送message:{"type":"cloud/status","id":18}

收到:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
{
  "success": true,
  "id": 18,
  "result": {
    "logged_in": true,
    "prefs": {
      "alexa_enabled": false,
      "google_secure_devices_pin": null,
      "google_enabled": false,
      "remote_enabled": false,
      "cloudhooks": {
        "xxx": {
          "cloudhook_id": "xxx",
          "managed": true,
          "cloudhook_url": "https://hooks.nabu.casa/xxxxxx",
          "webhook_id": "xxx"
        }
      },
      "cloud_user": "xx",
      "google_entity_configs": {}
    },
    "email": "EMAIL",
    "remote_certificate": null,
    "alexa_entities": {
      "include_entities": [],
      "exclude_domains": [],
      "include_domains": [],
      "exclude_entities": []
    },
    "cloud": "connecting",
    "remote_connected": false,
    "alexa_domains": [
      "fan",
      "automation",
      "group",
      "alert",
      "cover",
      "lock",
      "script",
      "sensor",
      "binary_sensor",
      "climate",
      "scene",
      "input_boolean",
      "switch",
      "media_player",
      "light"
    ],
    "remote_domain": null,
    "google_entities": {
      "include_entities": [],
      "exclude_domains": [],
      "include_domains": [],
      "exclude_entities": []
    }
  },
  "type": "result"
}

之后前端继续发送两条websocket消息:

{"type":"webhook/list","id":19}, 返回:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "success": true,
  "id": 19,
  "result": [
    {
      "domain": "locative",
      "name": "Locative",
      "webhook_id": "xxxx"
    }
  ],
  "type": "result"
}

{"type":"cloud/subscription","id":20}, 返回:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "success": true,
  "id": 20,
  "result": {
    "customer_exists": true,
    "renewal_active": false,
    "status": 200,
    "subscription": {
      "canceled_at": 1560481412,
      "cancel_at_period_end": true,
      "trial_end": 1563148800,
      "status": "trialing",
      "current_period_end": 1563148800
    },
    "human_description": "Trial user. Trial expires Jul 15, 2019.",
    "delete_requested": false,
    "provider": null,
    "source": null,
    "plan_renewal_date": 1563148800,
    "billing_plan_type": "trial"
  },
  "type": "result"
}

开启Remote Control

点击Remote Control 右边的按钮,将打开远程控制模式。点击之后前端发送websocket消息:

{"type":"cloud/remote/connect","id":20}, 返回内容同前头{"type":"cloud/status","id":18}相似

{"type":"cloud/status","id":21}, 返回内容同前头{"type":"cloud/status","id":18}相似

关闭Remote Control

{"type":"cloud/remote/disconnect","id":22}, 返回内容同前头{"type":"cloud/status","id":18}相似

打开显示在页面的链接:https://xxx.ui.nabu.casa, 可以进行远程控制了!控制界面完全相同,目前猜测是建立了一个透明管道,就像ngrok那样

开启alax

{"type":"cloud/update_prefs","alexa_enabled":true,"id":24}, 返回{"success": true, "id": 24, "result": null, "type": "result"}

后端分析

根据前端的websocket message,逆向找到对应的后端源码是比较简单的一件事。

我们重点关注一下handle{"type":"cloud/remote/connect","id":20}消息的后端源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@websocket_api.require_admin
@_require_cloud_login
@websocket_api.async_response
@_ws_handle_cloud_errors
@websocket_api.websocket_command({
    'type': 'cloud/remote/connect'
})
async def websocket_remote_connect(hass, connection, msg):
    """Handle request for connect remote."""
    cloud = hass.data[DOMAIN] # 
    await cloud.client.prefs.async_update(remote_enabled=True)
    await cloud.remote.connect()
    connection.send_result(msg['id'], _account_data(cloud))

nabucasa client部分对应的源码

阅读RemoteUI class可以发现cloud非常值得关注,cloud作为RemoteUI初始化参数传入,我们跟踪RemoteUI的初始化过程,可以追溯到:self.remote = RemoteUI(self), nabucasa client与云相关的所有秘密都可以从这儿找到。

云端分析

从前头的讨论我们感觉Home Assistant Cloud有些像ngrok server。使用ngrok好像也完全做得到这些事。 本质是把局域网服务暴露到外网。

远程页面如何通信

Remote Control现实的公网控制页面https://xxx.ui.nabu.casa/ 是如何控制我们的设备的呢,可以发现,它使用的websocket通道为 wss://xxx.ui.nabu.casa/api/websocket,采用的message和本地完全一样。

看起来是个透明代理。

从证书信息和后端源码可知证书使用 letsencrypt.org(有效期为3个月,会自动更新)

隐藏目录

登陆之后,观察.homeassistant/.cloud目录, 有以下文件:

  • acme_account.pem
  • acme_reg.json
  • production_auth.json
  • remote_fullchain.pem
  • remote_private.pem

.storage/cloud内容为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
    "data": {
        "alexa_enabled": false,
        "cloud_user": "xxx",
        "cloudhooks": {
            "xxx": {
                "cloudhook_id": "xxx",
                "cloudhook_url": "https://hooks.nabu.casa/xxx",
                "managed": true,
                "webhook_id": "xxx"
            }
        },
        "google_enabled": false,
        "google_secure_devices_pin": null,
        "remote_enabled": true
    },
    "key": "cloud",
    "version": 1
}

参考