Browse Source

yunbridge: add linux side python code

to make the bridge work we need to run an askfirst instance on the ttyS.
additionally add the lua scripts needed to make REST work. this is really ugly
code but it works. i already cleaned up to the original code, but there are still
issues such as a new luci session being created for each request.

Signed-off-by: John Crispin <blogic@openwrt.org>
John Crispin 9 years ago
parent
commit
2e57574f30

+ 48
- 0
utils/yunbridge/Makefile View File

@@ -0,0 +1,48 @@
1
+#
2
+# Copyright (C) 2006-2011 OpenWrt.org
3
+#
4
+# This is free software, licensed under the GNU General Public License v2.
5
+# See /LICENSE for more information.
6
+#
7
+
8
+include $(TOPDIR)/rules.mk
9
+
10
+PKG_NAME:=yunbridge
11
+PKG_VERSION:=160
12
+
13
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
14
+
15
+PKG_SOURCE_PROTO:=git
16
+PKG_SOURCE_URL:=https://github.com/arduino/YunBridge.git
17
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
18
+PKG_SOURCE_VERSION:=f2042052115e71ad2c91f77e78d21db8275fcdd6
19
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
20
+
21
+PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
22
+PKG_LICENSE:=GPL-2.0
23
+
24
+include $(INCLUDE_DIR)/package.mk
25
+
26
+define Package/yunbridge
27
+  SECTION:=utils
28
+  CATEGORY:=Utilities
29
+  TITLE:=Arduino YUN bridge library
30
+  URL:=http://arduino.cc/
31
+  DEPENDS:=+python
32
+endef
33
+
34
+define Package/yunbridge/description
35
+  Arduino YUN bridge library
36
+endef
37
+
38
+define Build/Compile
39
+	true
40
+endef
41
+
42
+define Package/yunbridge/install
43
+	mkdir -p $(1)/usr/lib/python2.7/bridge
44
+	$(CP) $(PKG_BUILD_DIR)/bridge/*.py $(1)/usr/lib/python2.7/bridge/
45
+	$(CP) ./files/* $(1)
46
+endef
47
+
48
+$(eval $(call BuildPackage,yunbridge))

+ 6
- 0
utils/yunbridge/files/etc/config/yunbridge View File

@@ -0,0 +1,6 @@
1
+config bridge config
2
+	option socket_timeout 5
3
+	option secure_rest_api false
4
+
5
+	# remove this line to activae the yunbridge
6
+	option disabled	1

+ 22
- 0
utils/yunbridge/files/etc/init.d/yunbridge View File

@@ -0,0 +1,22 @@
1
+#!/bin/sh /etc/rc.common
2
+# Copyright (C) 2013 OpenWrt.org
3
+
4
+# start after and stop before networking
5
+START=20
6
+STOP=89
7
+
8
+USE_PROCD=1
9
+
10
+service_triggers()
11
+{
12
+	procd_add_reload_trigger "yunbridge"
13
+}
14
+
15
+start_service()
16
+{
17
+	[ "$(uci -q get yunbridge.config.disabled)" = "1" ] && return 0
18
+	procd_open_instance
19
+	procd_set_param command "/sbin/yunbridge"
20
+	procd_set_param respawn
21
+	procd_close_instance
22
+}

+ 6
- 0
utils/yunbridge/files/sbin/yunbridge View File

@@ -0,0 +1,6 @@
1
+#!/bin/sh
2
+stty -F /dev/ttyS0 2500000 clocal cread cs8 -cstopb -parenb
3
+exec < /dev/ttyS0
4
+exec > /dev/ttyS0
5
+exec 2> /dev/ttyS0
6
+askfirst bin/ash --login

+ 75
- 0
utils/yunbridge/files/usr/bin/pretty-wifi-info.lua View File

@@ -0,0 +1,75 @@
1
+#!/usr/bin/lua
2
+
3
+local function get_basic_net_info(network, iface, accumulator)
4
+  local net = network:get_network(iface)
5
+  local device = net and net:get_interface()
6
+
7
+  if device then
8
+    accumulator["uptime"] = net:uptime()
9
+    accumulator["iface"] = device:name()
10
+    accumulator["mac"] = device:mac()
11
+    accumulator["rx_bytes"] = device:rx_bytes()
12
+    accumulator["tx_bytes"] = device:tx_bytes()
13
+    accumulator["ipaddrs"] = {}
14
+
15
+    for _, ipaddr in ipairs(device:ipaddrs()) do
16
+      accumulator.ipaddrs[#accumulator.ipaddrs + 1] = {
17
+        addr = ipaddr:host():string(),
18
+        netmask = ipaddr:mask():string()
19
+      }
20
+    end
21
+  end
22
+end
23
+
24
+local function get_wifi_info(network, iface, accumulator)
25
+  local net = network:get_wifinet(iface)
26
+
27
+  if net then
28
+    local dev = net:get_device()
29
+    if dev then
30
+      accumulator["mode"] = net:active_mode()
31
+      accumulator["ssid"] = net:active_ssid()
32
+      accumulator["encryption"] = net:active_encryption()
33
+      accumulator["quality"] = net:signal_percent()
34
+    end
35
+  end
36
+end
37
+
38
+local function collect_wifi_info()
39
+  local network = require"luci.model.network".init()
40
+  local accumulator = {}
41
+  get_basic_net_info(network, "lan", accumulator)
42
+  get_wifi_info(network, "wlan0", accumulator)
43
+  return accumulator
44
+end
45
+
46
+local info = collect_wifi_info()
47
+
48
+print("Current WiFi configuration")
49
+if info.ssid then
50
+  print("SSID: " .. info.ssid)
51
+end
52
+if info.mode then
53
+  print("Mode: " .. info.mode)
54
+end
55
+if info.quality then
56
+  print("Signal: " .. info.quality .. "%")
57
+end
58
+if info.encryption then
59
+  print("Encryption method: " .. info.encryption)
60
+end
61
+if info.iface then
62
+  print("Interface name: " .. info.iface)
63
+end
64
+if info.uptime then
65
+  print("Active for: " .. math.floor(info.uptime / 60) .. " minutes")
66
+end
67
+if #info.ipaddrs > 0 then
68
+  print("IP address: " .. info.ipaddrs[1].addr .. "/" .. info.ipaddrs[1].netmask)
69
+end
70
+if info.mac then
71
+  print("MAC address: " .. info.mac)
72
+end
73
+if info.rx_bytes and info.tx_bytes then
74
+  print("RX/TX: " .. math.floor(info.rx_bytes / 1024) .. "/" .. math.floor(info.tx_bytes / 1024) .. " KBs")
75
+end

+ 414
- 0
utils/yunbridge/files/usr/lib/lua/luci/controller/arduino/index.lua View File

@@ -0,0 +1,414 @@
1
+--[[
2
+This file is part of YunWebUI.
3
+
4
+YunWebUI is free software; you can redistribute it and/or modify
5
+it under the terms of the GNU General Public License as published by
6
+the Free Software Foundation; either version 2 of the License, or
7
+(at your option) any later version.
8
+
9
+This program is distributed in the hope that it will be useful,
10
+but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+GNU General Public License for more details.
13
+
14
+You should have received a copy of the GNU General Public License
15
+along with this program; if not, write to the Free Software
16
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
+
18
+As a special exception, you may use this file as part of a free software
19
+library without restriction.  Specifically, if other files instantiate
20
+templates or use macros or inline functions from this file, or you compile
21
+this file and link it with other files to produce an executable, this
22
+file does not by itself cause the resulting executable to be covered by
23
+the GNU General Public License.  This exception does not however
24
+invalidate any other reasons why the executable file might be covered by
25
+the GNU General Public License.
26
+
27
+Copyright 2013 Arduino LLC (http://www.arduino.cc/)
28
+]]
29
+
30
+module("luci.controller.arduino.index", package.seeall)
31
+
32
+local function not_nil_or_empty(value)
33
+  return value and value ~= ""
34
+end
35
+
36
+local function get_first(cursor, config, type, option)
37
+  return cursor:get_first(config, type, option)
38
+end
39
+
40
+local function set_first(cursor, config, type, option, value)
41
+  cursor:foreach(config, type, function(s)
42
+    if s[".type"] == type then
43
+      cursor:set(config, s[".name"], option, value)
44
+    end
45
+  end)
46
+end
47
+
48
+
49
+local function to_key_value(s)
50
+  local parts = luci.util.split(s, ":")
51
+  parts[1] = luci.util.trim(parts[1])
52
+  parts[2] = luci.util.trim(parts[2])
53
+  return parts[1], parts[2]
54
+end
55
+
56
+function http_error(code, text)
57
+  luci.http.prepare_content("text/plain")
58
+  luci.http.status(code)
59
+  if text then
60
+    luci.http.write(text)
61
+  end
62
+end
63
+
64
+function index()
65
+  function luci.dispatcher.authenticator.arduinoauth(validator, accs, default)
66
+    require("luci.controller.arduino.index")
67
+
68
+    local user = luci.http.formvalue("username")
69
+    local pass = luci.http.formvalue("password")
70
+    local basic_auth = luci.http.getenv("HTTP_AUTHORIZATION")
71
+
72
+    if user and validator(user, pass) then
73
+      return user
74
+    end
75
+
76
+    if basic_auth and basic_auth ~= "" then
77
+      local decoded_basic_auth = nixio.bin.b64decode(string.sub(basic_auth, 7))
78
+      user = string.sub(decoded_basic_auth, 0, string.find(decoded_basic_auth, ":") - 1)
79
+      pass = string.sub(decoded_basic_auth, string.find(decoded_basic_auth, ":") + 1)
80
+    end
81
+
82
+    if user then
83
+      if #pass ~= 64 and validator(user, pass) then
84
+        return user
85
+      elseif #pass == 64 then
86
+        local uci = luci.model.uci.cursor()
87
+        uci:load("yunbridge")
88
+        local stored_encrypted_pass = uci:get_first("yunbridge", "bridge", "password")
89
+        if pass == stored_encrypted_pass then
90
+          return user
91
+        end
92
+      end
93
+    end
94
+
95
+    luci.http.header("WWW-Authenticate", "Basic realm=\"yunbridge\"")
96
+    luci.http.status(401)
97
+
98
+    return false
99
+  end
100
+
101
+  local function make_entry(path, target, title, order)
102
+    local page = entry(path, target, title, order)
103
+    page.leaf = true
104
+    return page
105
+  end
106
+
107
+  -- web panel
108
+  local webpanel = entry({ "webpanel" }, alias("webpanel", "go_to_homepage"), _("%s Web Panel") % luci.sys.hostname(), 10)
109
+  webpanel.sysauth = "root"
110
+  webpanel.sysauth_authenticator = "arduinoauth"
111
+
112
+  make_entry({ "webpanel", "go_to_homepage" }, call("go_to_homepage"), nil)
113
+
114
+  --api security level
115
+  local uci = luci.model.uci.cursor()
116
+  uci:load("yunbridge")
117
+  local secure_rest_api = uci:get_first("yunbridge", "bridge", "secure_rest_api")
118
+  local rest_api_sysauth = false
119
+  if secure_rest_api == "true" then
120
+    rest_api_sysauth = webpanel.sysauth
121
+  end
122
+
123
+  --storage api
124
+  local data_api = node("data")
125
+  data_api.sysauth = rest_api_sysauth
126
+  data_api.sysauth_authenticator = webpanel.sysauth_authenticator
127
+  make_entry({ "data", "get" }, call("storage_send_request"), nil).sysauth = rest_api_sysauth
128
+  make_entry({ "data", "put" }, call("storage_send_request"), nil).sysauth = rest_api_sysauth
129
+  make_entry({ "data", "delete" }, call("storage_send_request"), nil).sysauth = rest_api_sysauth
130
+  local mailbox_api = node("mailbox")
131
+  mailbox_api.sysauth = rest_api_sysauth
132
+  mailbox_api.sysauth_authenticator = webpanel.sysauth_authenticator
133
+  make_entry({ "mailbox" }, call("build_bridge_mailbox_request"), nil).sysauth = rest_api_sysauth
134
+
135
+  --plain socket endpoint
136
+  local plain_socket_endpoint = make_entry({ "arduino" }, call("board_plain_socket"), nil)
137
+  plain_socket_endpoint.sysauth = rest_api_sysauth
138
+  plain_socket_endpoint.sysauth_authenticator = webpanel.sysauth_authenticator
139
+end
140
+
141
+function go_to_homepage()
142
+  luci.http.redirect("/index.html")
143
+end
144
+
145
+local function build_bridge_request(command, params)
146
+
147
+  local bridge_request = {
148
+    command = command
149
+  }
150
+
151
+  if command == "raw" then
152
+    params = table.concat(params, "/")
153
+    if not_nil_or_empty(params) then
154
+      bridge_request["data"] = params
155
+    end
156
+    return bridge_request
157
+  end
158
+
159
+  if command == "get" then
160
+    if not_nil_or_empty(params[1]) then
161
+      bridge_request["key"] = params[1]
162
+    end
163
+    return bridge_request
164
+  end
165
+
166
+  if command == "put" and not_nil_or_empty(params[1]) and params[2] then
167
+    bridge_request["key"] = params[1]
168
+    bridge_request["value"] = params[2]
169
+    return bridge_request
170
+  end
171
+
172
+  if command == "delete" and not_nil_or_empty(params[1]) then
173
+    bridge_request["key"] = params[1]
174
+    return bridge_request
175
+  end
176
+
177
+  return nil
178
+end
179
+
180
+local function extract_jsonp_param(query_string)
181
+  if not not_nil_or_empty(query_string) then
182
+    return nil
183
+  end
184
+
185
+  local qs_parts = string.split(query_string, "&")
186
+  for idx, value in ipairs(qs_parts) do
187
+    if string.find(value, "jsonp") == 1 or string.find(value, "callback") == 1 then
188
+      return string.sub(value, string.find(value, "=") + 1)
189
+    end
190
+  end
191
+end
192
+
193
+local function parts_after(url_part)
194
+  local url = luci.http.getenv("PATH_INFO")
195
+  local url_after_part = string.find(url, "/", string.find(url, url_part) + 1)
196
+  if not url_after_part then
197
+    return {}
198
+  end
199
+  return luci.util.split(string.sub(url, url_after_part + 1), "/")
200
+end
201
+
202
+function storage_send_request()
203
+  local method = luci.http.getenv("REQUEST_METHOD")
204
+  local jsonp_callback = extract_jsonp_param(luci.http.getenv("QUERY_STRING"))
205
+  local parts = parts_after("data")
206
+  local command = parts[1]
207
+  if not command or command == "" then
208
+    luci.http.status(404)
209
+    return
210
+  end
211
+  local params = {}
212
+  for idx, param in ipairs(parts) do
213
+    if idx > 1 and not_nil_or_empty(param) then
214
+      table.insert(params, param)
215
+    end
216
+  end
217
+
218
+  -- TODO check method?
219
+  local bridge_request = build_bridge_request(command, params)
220
+  if not bridge_request then
221
+    luci.http.status(403)
222
+    return
223
+  end
224
+
225
+  local uci = luci.model.uci.cursor()
226
+  uci:load("yunbridge")
227
+  local socket_timeout = uci:get_first("yunbridge", "bridge", "socket_timeout", 5)
228
+
229
+  local sock, code, msg = nixio.connect("127.0.0.1", 5700)
230
+  if not sock then
231
+    code = code or ""
232
+    msg = msg or ""
233
+    http_error(500, "nil socket, " .. code .. " " .. msg)
234
+    return
235
+  end
236
+
237
+  sock:setopt("socket", "sndtimeo", socket_timeout)
238
+  sock:setopt("socket", "rcvtimeo", socket_timeout)
239
+  sock:setopt("tcp", "nodelay", 1)
240
+
241
+  local json = require("luci.json")
242
+
243
+  sock:write(json.encode(bridge_request))
244
+  sock:writeall("\n")
245
+
246
+  local response_text = {}
247
+  while true do
248
+    local bytes = sock:recv(4096)
249
+    if bytes and #bytes > 0 then
250
+      table.insert(response_text, bytes)
251
+    end
252
+
253
+    local json_response = json.decode(table.concat(response_text))
254
+    if json_response then
255
+      sock:close()
256
+      luci.http.status(200)
257
+      if jsonp_callback then
258
+        luci.http.prepare_content("application/javascript")
259
+        luci.http.write(jsonp_callback)
260
+        luci.http.write("(")
261
+        luci.http.write_json(json_response)
262
+        luci.http.write(");")
263
+      else
264
+        luci.http.prepare_content("application/json")
265
+        luci.http.write(json.encode(json_response))
266
+      end
267
+      return
268
+    end
269
+
270
+    if not bytes or #response_text == 0 then
271
+      sock:close()
272
+      http_error(500, "Empty response")
273
+      return
274
+    end
275
+  end
276
+
277
+  sock:close()
278
+end
279
+
280
+function board_plain_socket()
281
+  local function send_response(response_text, jsonp_callback)
282
+    if not response_text then
283
+      luci.http.status(500)
284
+      return
285
+    end
286
+
287
+    local rows = luci.util.split(response_text, "\r\n")
288
+    if #rows == 1 or string.find(rows[1], "Status") ~= 1 then
289
+      luci.http.prepare_content("text/plain")
290
+      luci.http.status(200)
291
+      luci.http.write(response_text)
292
+      return
293
+    end
294
+
295
+    local body_start_at_idx = -1
296
+    local content_type = "text/plain"
297
+    for idx, row in ipairs(rows) do
298
+      if row == "" then
299
+        body_start_at_idx = idx
300
+        break
301
+      end
302
+
303
+      local key, value = to_key_value(row)
304
+      if string.lower(key) == "status" then
305
+        luci.http.status(tonumber(value))
306
+      elseif string.lower(key) == "content-type" then
307
+        content_type = value
308
+      else
309
+        luci.http.header(key, value)
310
+      end
311
+    end
312
+
313
+    local response_body = table.concat(rows, "\r\n", body_start_at_idx + 1)
314
+    if content_type == "application/json" and jsonp_callback then
315
+      local json = require("luci.json")
316
+      luci.http.prepare_content("application/javascript")
317
+      luci.http.write(jsonp_callback)
318
+      luci.http.write("(")
319
+      luci.http.write_json(json.decode(response_body))
320
+      luci.http.write(");")
321
+    else
322
+      luci.http.prepare_content(content_type)
323
+      luci.http.write(response_body)
324
+    end
325
+  end
326
+
327
+  local method = luci.http.getenv("REQUEST_METHOD")
328
+  local jsonp_callback = extract_jsonp_param(luci.http.getenv("QUERY_STRING"))
329
+  local parts = parts_after("arduino")
330
+  local params = {}
331
+  for idx, param in ipairs(parts) do
332
+    if not_nil_or_empty(param) then
333
+      table.insert(params, param)
334
+    end
335
+  end
336
+
337
+  if #params == 0 then
338
+    luci.http.status(404)
339
+    return
340
+  end
341
+
342
+  params = table.concat(params, "/")
343
+
344
+  local uci = luci.model.uci.cursor()
345
+  uci:load("yunbridge")
346
+  local socket_timeout = uci:get_first("yunbridge", "bridge", "socket_timeout", 5)
347
+
348
+  local sock, code, msg = nixio.connect("127.0.0.1", 5555)
349
+  if not sock then
350
+    code = code or ""
351
+    msg = msg or ""
352
+    http_error(500, "Could not connect to YunServer " .. code .. " " .. msg)
353
+    return
354
+  end
355
+
356
+  sock:setopt("socket", "sndtimeo", socket_timeout)
357
+  sock:setopt("socket", "rcvtimeo", socket_timeout)
358
+  sock:setopt("tcp", "nodelay", 1)
359
+
360
+  sock:write(params)
361
+  sock:writeall("\r\n")
362
+
363
+  local response_text = sock:readall()
364
+  sock:close()
365
+
366
+  send_response(response_text, jsonp_callback)
367
+end
368
+
369
+function build_bridge_mailbox_request()
370
+  local method = luci.http.getenv("REQUEST_METHOD")
371
+  local jsonp_callback = extract_jsonp_param(luci.http.getenv("QUERY_STRING"))
372
+  local parts = parts_after("mailbox")
373
+  local params = {}
374
+  for idx, param in ipairs(parts) do
375
+    if not_nil_or_empty(param) then
376
+      table.insert(params, param)
377
+    end
378
+  end
379
+
380
+  if #params == 0 then
381
+    luci.http.status(400)
382
+    return
383
+  end
384
+
385
+  local bridge_request = build_bridge_request("raw", params)
386
+  if not bridge_request then
387
+    luci.http.status(403)
388
+    return
389
+  end
390
+
391
+  local uci = luci.model.uci.cursor()
392
+  uci:load("yunbridge")
393
+  local socket_timeout = uci:get_first("yunbridge", "bridge", "socket_timeout", 5)
394
+
395
+  local sock, code, msg = nixio.connect("127.0.0.1", 5700)
396
+  if not sock then
397
+    code = code or ""
398
+    msg = msg or ""
399
+    http_error(500, "nil socket, " .. code .. " " .. msg)
400
+    return
401
+  end
402
+
403
+  sock:setopt("socket", "sndtimeo", socket_timeout)
404
+  sock:setopt("socket", "rcvtimeo", socket_timeout)
405
+  sock:setopt("tcp", "nodelay", 1)
406
+
407
+  local json = require("luci.json")
408
+
409
+  sock:write(json.encode(bridge_request))
410
+  sock:writeall("\n")
411
+  sock:close()
412
+
413
+  luci.http.status(200)
414
+end

+ 199
- 0
utils/yunbridge/files/usr/lib/lua/luci/sha256.lua View File

@@ -0,0 +1,199 @@
1
+--
2
+--  Code merged by gravityscore at http://pastebin.com/gsFrNjbt
3
+--
4
+--  Adaptation of the Secure Hashing Algorithm (SHA-244/256)
5
+--  Found Here: http://lua-users.org/wiki/SecureHashAlgorithm
6
+--  
7
+--  Using an adapted version of the bit library
8
+--  Found Here: https://bitbucket.org/Boolsheet/bslf/src/1ee664885805/bit.lua
9
+--  
10
+
11
+module("luci.sha256", package.seeall)
12
+
13
+local MOD = 2 ^ 32
14
+local MODM = MOD - 1
15
+
16
+local function memoize(f)
17
+  local mt = {}
18
+  local t = setmetatable({}, mt)
19
+  function mt:__index(k)
20
+    local v = f(k)
21
+    t[k] = v
22
+    return v
23
+  end
24
+
25
+  return t
26
+end
27
+
28
+local function make_bitop_uncached(t, m)
29
+  local function bitop(a, b)
30
+    local res, p = 0, 1
31
+    while a ~= 0 and b ~= 0 do
32
+      local am, bm = a % m, b % m
33
+      res = res + t[am][bm] * p
34
+      a = (a - am) / m
35
+      b = (b - bm) / m
36
+      p = p * m
37
+    end
38
+    res = res + (a + b) * p
39
+    return res
40
+  end
41
+
42
+  return bitop
43
+end
44
+
45
+local function make_bitop(t)
46
+  local op1 = make_bitop_uncached(t, 2 ^ 1)
47
+  local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end)
48
+  return make_bitop_uncached(op2, 2 ^ (t.n or 1))
49
+end
50
+
51
+local bxor1 = make_bitop({ [0] = { [0] = 0, [1] = 1 }, [1] = { [0] = 1, [1] = 0 }, n = 4 })
52
+
53
+local function bxor(a, b, c, ...)
54
+  local z = nil
55
+  if b then
56
+    a = a % MOD
57
+    b = b % MOD
58
+    z = bxor1(a, b)
59
+    if c then z = bxor(z, c, ...) end
60
+    return z
61
+  elseif a then return a % MOD
62
+  else return 0
63
+  end
64
+end
65
+
66
+local function band(a, b, c, ...)
67
+  local z
68
+  if b then
69
+    a = a % MOD
70
+    b = b % MOD
71
+    z = ((a + b) - bxor1(a, b)) / 2
72
+    if c then z = bit32_band(z, c, ...) end
73
+    return z
74
+  elseif a then return a % MOD
75
+  else return MODM
76
+  end
77
+end
78
+
79
+local function bnot(x) return (-1 - x) % MOD end
80
+
81
+local function rshift1(a, disp)
82
+  if disp < 0 then return lshift(a, -disp) end
83
+  return math.floor(a % 2 ^ 32 / 2 ^ disp)
84
+end
85
+
86
+local function rshift(x, disp)
87
+  if disp > 31 or disp < -31 then return 0 end
88
+  return rshift1(x % MOD, disp)
89
+end
90
+
91
+local function lshift(a, disp)
92
+  if disp < 0 then return rshift(a, -disp) end
93
+  return (a * 2 ^ disp) % 2 ^ 32
94
+end
95
+
96
+local function rrotate(x, disp)
97
+  x = x % MOD
98
+  disp = disp % 32
99
+  local low = band(x, 2 ^ disp - 1)
100
+  return rshift(x, disp) + lshift(low, 32 - disp)
101
+end
102
+
103
+local k = {
104
+  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
105
+  0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
106
+  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
107
+  0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
108
+  0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
109
+  0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
110
+  0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
111
+  0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
112
+  0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
113
+  0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
114
+  0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
115
+  0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
116
+  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
117
+  0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
118
+  0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
119
+  0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
120
+}
121
+
122
+local function str2hexa(s)
123
+  return (string.gsub(s, ".", function(c) return string.format("%02x", string.byte(c)) end))
124
+end
125
+
126
+local function num2s(l, n)
127
+  local s = ""
128
+  for i = 1, n do
129
+    local rem = l % 256
130
+    s = string.char(rem) .. s
131
+    l = (l - rem) / 256
132
+  end
133
+  return s
134
+end
135
+
136
+local function s232num(s, i)
137
+  local n = 0
138
+  for i = i, i + 3 do n = n * 256 + string.byte(s, i) end
139
+  return n
140
+end
141
+
142
+local function preproc(msg, len)
143
+  local extra = 64 - ((len + 9) % 64)
144
+  len = num2s(8 * len, 8)
145
+  msg = msg .. "\128" .. string.rep("\0", extra) .. len
146
+  assert(#msg % 64 == 0)
147
+  return msg
148
+end
149
+
150
+local function initH256(H)
151
+  H[1] = 0x6a09e667
152
+  H[2] = 0xbb67ae85
153
+  H[3] = 0x3c6ef372
154
+  H[4] = 0xa54ff53a
155
+  H[5] = 0x510e527f
156
+  H[6] = 0x9b05688c
157
+  H[7] = 0x1f83d9ab
158
+  H[8] = 0x5be0cd19
159
+  return H
160
+end
161
+
162
+local function digestblock(msg, i, H)
163
+  local w = {}
164
+  for j = 1, 16 do w[j] = s232num(msg, i + (j - 1) * 4) end
165
+  for j = 17, 64 do
166
+    local v = w[j - 15]
167
+    local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))
168
+    v = w[j - 2]
169
+    w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))
170
+  end
171
+
172
+  local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
173
+  for i = 1, 64 do
174
+    local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))
175
+    local maj = bxor(band(a, b), band(a, c), band(b, c))
176
+    local t2 = s0 + maj
177
+    local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))
178
+    local ch = bxor(band(e, f), band(bnot(e), g))
179
+    local t1 = h + s1 + ch + k[i] + w[i]
180
+    h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2
181
+  end
182
+
183
+  H[1] = band(H[1] + a)
184
+  H[2] = band(H[2] + b)
185
+  H[3] = band(H[3] + c)
186
+  H[4] = band(H[4] + d)
187
+  H[5] = band(H[5] + e)
188
+  H[6] = band(H[6] + f)
189
+  H[7] = band(H[7] + g)
190
+  H[8] = band(H[8] + h)
191
+end
192
+
193
+function sha256(msg)
194
+  msg = preproc(msg, #msg)
195
+  local H = initH256({})
196
+  for i = 1, #msg, 64 do digestblock(msg, i, H) end
197
+  return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) ..
198
+          num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4))
199
+end

+ 18
- 0
utils/yunbridge/patches/000-scripts.patch View File

@@ -0,0 +1,18 @@
1
+--- a/bridge/packet.py
2
++++ b/bridge/packet.py
3
+@@ -93,12 +93,12 @@
4
+     
5
+   def run(self, data):
6
+     if data[0] != 'X':
7
+-      call(['/usr/bin/blink-start', '100'])
8
++      #call(['/usr/bin/blink-start', '100'])
9
+       return chr(1)
10
+     if data[1:4] != '100':
11
+-      call(['/usr/bin/blink-start', '100'])
12
++      #call(['/usr/bin/blink-start', '100'])
13
+       return chr(2)
14
+-    call(['/usr/bin/blink-stop'])
15
++    #call(['/usr/bin/blink-stop'])
16
+     return chr(0) + '160' # send the actual bridge version
17
+     
18
+ class PacketReader: