ruby_home 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6fb157eb26583418aa02ef31fe2b4ed2f8f40f8cb57e46f78e7603cdd531256b
4
- data.tar.gz: 5ed756570a2e0f3992a0b4b53eb0521bc94d7c46f55e5318a80e6bf74da27304
3
+ metadata.gz: cace8911ec7e8999b154e2bbcf7794ff7e9ca890b1b53fb8167091c316565bc6
4
+ data.tar.gz: 9f623241d8dd6bbca8e504919af18bd2084a722f5c9ee33a701714cbd82f73c1
5
5
  SHA512:
6
- metadata.gz: a8732ab9a3caa1e9d61a371bbed0495eb523d6e0b1e0c248f1f7f1fc7d6ab6848ccaa8a5105a78214ad4375bb15df57e84df00d664cf4ad554bbab89a53e375d
7
- data.tar.gz: 3f0b97b56c9785b1664a5fa7885407a37ae75bce6924f1b8c7dbee6b72ab3037b8037f5872c38e7fad6ed5bd88fa34f73f955a70138774b6b1fe18bfe218956a
6
+ metadata.gz: a4787d16e0be2c98a35d8428ef90ef83cd8462f2fa9189f6243367ef8eca006812a86c26d4c29afa5c3d09827401fb61909f5320b7e1d5ac2d4c5ab0d3e95f78
7
+ data.tar.gz: 138ef40f9cf8e9c0fa8820c2611d1bf70dd4398578e40139165359d93558fe7df8205676fa660426debc49c9852d7f42d770f9a4b99cb9bf4d224bec21821384
data/README.md CHANGED
@@ -17,7 +17,7 @@ For OS X users, libsodium is available via homebrew and can be installed with:
17
17
 
18
18
  brew install libsodium
19
19
 
20
- For Debian users, libsodium is available both via apt:
20
+ For Debian users, libsodium is available via apt:
21
21
 
22
22
  sudo apt-get install libsodium-dev
23
23
 
@@ -33,13 +33,13 @@ And then execute:
33
33
 
34
34
  $ bundle
35
35
 
36
- Or install it yourself as:
36
+ Or install it yourself with:
37
37
 
38
38
  $ gem install ruby_home
39
39
 
40
40
  ## Basic usage
41
41
 
42
- Create a fan with an on/off switch.
42
+ Create a fan with an on/off switch:
43
43
 
44
44
  ```ruby
45
45
  require 'ruby_home'
@@ -60,7 +60,7 @@ RubyHome.run
60
60
 
61
61
  ## Configuration
62
62
 
63
- The configuration options can be set by using the `configure` helper
63
+ The configuration options can be set by using the `configure` helper:
64
64
 
65
65
  ```ruby
66
66
  RubyHome.configure do |c|
@@ -74,7 +74,7 @@ The following is the full list of available configuration options:
74
74
  |---|---|---|---|---|
75
75
  | `discovery_name` | The user-visible name of the accessory | `"RubyHome"` | `"My Home"` | String |
76
76
  | `model_name` | The model name of the accessory | `"RubyHome"` | `"Device1,1"` | String |
77
- | `password` | Used for pairing must conform to the format XXX-XX-XXX where each X is a 0-9 digit and dashes are required | Randomly generated | `"101-48-005"` | String |
77
+ | `password` | Used for pairing, must conform to the format XXX-XX-XXX where each X is a 0-9 digit and dashes are required | Randomly generated | `"101-48-005"` | String |
78
78
  | `host` | The hostname or IP address of the interface to listen on | `"0.0.0.0"` | `"192.168.0.2"` | String |
79
79
  | `port` | The port that should be used when starting the built-in web server | `4567` | `8080` | Integer |
80
80
 
@@ -117,9 +117,9 @@ RubyHome.run
117
117
 
118
118
  ## Updating a characteristics value
119
119
 
120
- If you have a service with characteristics that can be changed outside of Ruby Home. You'll want to keep Ruby Home in sync with these modifications. Otherwise, the characteristics current value won't correspond with reality. The simplest way to do this is a background job that periodically polls the devices current status and updates the corresponding characteristics value if it's changed.
120
+ If you have a service with characteristics that can be changed outside of Ruby Home, you'll want to keep Ruby Home in sync with these modifications. Otherwise, the characteristics current value won't correspond with reality. The simplest way to do this is a background job that periodically polls the devices current status and updates the corresponding characteristics value if it's changed.
121
121
 
122
- Given a fan which can be switched on / off with a remote control. Which has a JSON API endpoint at http://example.org/fan_status.json that returns its current status `{ "on": true }` or `{ "on": false }`. We can spawn a thread that keeps polling the fans current status and if its changed update our fan service "on" characteristic.
122
+ Given a fan which can be switched on / off with a remote control, which has a JSON API endpoint at http://example.org/fan_status.json that returns its current status `{ "on": true }` or `{ "on": false }`, we can spawn a thread that keeps polling the fans current status and if it's changed update our fan service "on" characteristic.
123
123
 
124
124
  ```ruby
125
125
  require 'json'
@@ -150,7 +150,7 @@ RubyHome.run
150
150
 
151
151
  ## More examples
152
152
 
153
- ### Create a garage door opener.
153
+ ### Create a garage door opener
154
154
 
155
155
  ```ruby
156
156
  require 'ruby_home'
@@ -171,7 +171,7 @@ end
171
171
  RubyHome.run
172
172
  ```
173
173
 
174
- ### Create a thermostat.
174
+ ### Create a thermostat
175
175
 
176
176
  ```ruby
177
177
  require 'ruby_home'
@@ -6,6 +6,8 @@ module RubyHome
6
6
  end
7
7
 
8
8
  def update
9
+ return if RbConfig::CONFIG['target_os'] =~ /linux/
10
+
9
11
  dnssd_service.add_record(DNSSD::Record::TXT, text_record.encode)
10
12
  end
11
13
 
@@ -0,0 +1,4 @@
1
+ module RubyHome
2
+ class RubyHomeError < StandardError; end
3
+ class UnknownValueError < RubyHomeError; end
4
+ end
@@ -35,29 +35,20 @@ module RubyHome
35
35
  Host: bind_address,
36
36
  ServerSoftware: 'RubyHome',
37
37
  Logger: server_logger,
38
- AccessLog: access_logger
38
+ AccessLog: []
39
39
  }
40
40
  end
41
41
 
42
42
  def server_logger
43
- if ENV['DEBUG']
43
+ if ENV['DEBUG'] == 'debug'
44
44
  WEBrick::Log::new(STDOUT, WEBrick::BasicLog::DEBUG)
45
+ elsif ENV['DEBUG'] == 'info'
46
+ WEBrick::Log::new(STDOUT, WEBrick::BasicLog::INFO)
45
47
  else
46
48
  WEBrick::Log::new("/dev/null", WEBrick::BasicLog::WARN)
47
49
  end
48
50
  end
49
51
 
50
- def access_logger
51
- if ENV['DEBUG']
52
- [
53
- [ STDOUT, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
54
- [ STDOUT, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
55
- ]
56
- else
57
- []
58
- end
59
- end
60
-
61
52
  def bind_address
62
53
  configuration.host
63
54
  end
@@ -13,7 +13,17 @@ module RubyHome
13
13
  end
14
14
 
15
15
  def valid_values
16
- template.constraints.fetch('ValidValues')
16
+ defined_values || range_values || raise(UnknownValueError, "Constraint contains an unrecognized list of values: #{template.constraints.inspect }")
17
+ end
18
+
19
+ def defined_values
20
+ template.constraints.dig('ValidValues')
21
+ end
22
+
23
+ def range_values
24
+ if min = template.constraints.dig('MinimumValue')
25
+ { min.to_s => min }
26
+ end
17
27
  end
18
28
  end
19
29
  end
@@ -5,10 +5,17 @@ module RubyHome
5
5
  class ApplicationController < Sinatra::Base
6
6
  disable :protection
7
7
 
8
- if ENV['DEBUG']
9
- enable :logging
10
- set :logger, Logger.new(STDOUT)
8
+ logger = Logger.new(STDOUT)
9
+ logger.level = case ENV['DEBUG']
10
+ when 'debug'
11
+ Logger::DEBUG
12
+ when 'info'
13
+ Logger::INFO
14
+ else
15
+ Logger::WARN
11
16
  end
17
+ set :logger, logger
18
+ enable :logging if ENV['DEBUG']
12
19
 
13
20
  before do
14
21
  logger.debug "Session"
@@ -38,9 +38,9 @@ module RubyHome
38
38
  device_proof: unpack_request[:proof],
39
39
  srp_session: session.srp_session,
40
40
  public_key: unpack_request[:public_key],
41
- )
41
+ ).run
42
42
 
43
- if verify_srp.valid?
43
+ if verify_srp.success?
44
44
  session.session_key = verify_srp.session_key
45
45
  session.srp_session = nil
46
46
 
@@ -48,18 +48,16 @@ module RubyHome
48
48
  end
49
49
 
50
50
  def verify_finish_response
51
- encrypted_data = unpack_request[:encrypted_data]
52
-
53
- chacha20poly1305ietf = HAP::Crypto::ChaCha20Poly1305.new(session.session_key)
54
- nonce = HexHelper.pad('PV-Msg03')
55
- decrypted_data = chacha20poly1305ietf.decrypt(nonce, encrypted_data)
56
- unpacked_decrypted_data = TLV.decode(decrypted_data)
57
-
58
- if accessory_info.paired_clients.any? {|h| h[:identifier] == unpacked_decrypted_data[:identifier]}
59
- shared_secret = HAP::Crypto::SessionKey.new(session.shared_secret)
60
-
61
- session.controller_to_accessory_key = shared_secret.controller_to_accessory_key
62
- session.accessory_to_controller_key = shared_secret.accessory_to_controller_key
51
+ verify_finish = VerifyFinishService.new(
52
+ encrypted_data: unpack_request[:encrypted_data],
53
+ session_key: session.session_key,
54
+ shared_secret: session.shared_secret,
55
+ accessory_info: accessory_info
56
+ ).run
57
+
58
+ if verify_finish.success?
59
+ session.controller_to_accessory_key = verify_finish.controller_to_accessory_key
60
+ session.accessory_to_controller_key = verify_finish.accessory_to_controller_key
63
61
 
64
62
  session.session_key = nil
65
63
  session.shared_secret = nil
@@ -0,0 +1,56 @@
1
+ module RubyHome
2
+ class VerifyFinishService
3
+ def initialize(accessory_info: , encrypted_data: , session_key:, shared_secret:)
4
+ @accessory_info = accessory_info
5
+ @encrypted_data = encrypted_data
6
+ @session_key = session_key
7
+ @shared_secret = HAP::Crypto::SessionKey.new(shared_secret)
8
+ end
9
+
10
+ def run
11
+ if paired_client_exists?
12
+ RubyHome.dns_service.update
13
+
14
+ OpenStruct.new(
15
+ success?: true,
16
+ controller_to_accessory_key: shared_secret.controller_to_accessory_key,
17
+ accessory_to_controller_key: shared_secret.accessory_to_controller_key
18
+ )
19
+ else
20
+ OpenStruct.new(success?: false)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ NONCE = -'PV-Msg03'
27
+
28
+ attr_reader :accessory_info, :encrypted_data, :session_key, :shared_secret
29
+
30
+ def paired_client_exists?
31
+ accessory_info.paired_clients.any? do |paired_client|
32
+ paired_client[:identifier] == identifier
33
+ end
34
+ end
35
+
36
+ def chacha20poly1305
37
+ HAP::Crypto::ChaCha20Poly1305.new(session_key)
38
+ end
39
+
40
+ def nonce
41
+ HexHelper.pad(NONCE)
42
+ end
43
+
44
+ def decrypted_data
45
+ chacha20poly1305.decrypt(nonce, encrypted_data)
46
+ end
47
+
48
+ def unpacked_decrypted_data
49
+ TLV.decode(decrypted_data)
50
+ end
51
+
52
+ def identifier
53
+ unpacked_decrypted_data[:identifier]
54
+ end
55
+ end
56
+ end
@@ -1,57 +1,48 @@
1
1
  module RubyHome
2
2
  class VerifySRPService
3
- def initialize(public_key: , device_proof: , srp_session: )
4
- @device_proof = device_proof
3
+ def initialize(device_proof: , public_key: , srp_session: )
4
+ @device_proof_bytes = device_proof.to_s.unpack1('H*')
5
+ @public_key_bytes = public_key.to_s.unpack1('H*')
5
6
  @srp_session = srp_session
6
- @public_key = public_key
7
7
  end
8
8
 
9
- def valid?
10
- return false unless public_key
11
- return false unless device_proof
12
- return false unless srp_session
13
- return false unless valid_session?
14
-
15
- true
16
- end
17
-
18
- def session_key
19
- srp_verifier.K
20
- end
21
-
22
- def server_proof
23
- verify_session_bytes
9
+ def run
10
+ if valid_session?
11
+ OpenStruct.new(
12
+ success?: true,
13
+ session_key: session_key,
14
+ server_proof: verify_session_bytes
15
+ )
16
+ else
17
+ OpenStruct.new(success?: false)
18
+ end
24
19
  end
25
20
 
26
21
  private
27
22
 
28
- def valid_session?
29
- !!verify_session
30
- end
31
-
32
- def verify_session_bytes
33
- [verify_session].pack('H*')
34
- end
23
+ def valid_session?
24
+ !!verify_session
25
+ end
35
26
 
36
- def verify_session
37
- @_verify_session ||= srp_verifier.verify_session(
38
- srp_session.merge({A: public_key_bytes}),
39
- device_proof_bytes
40
- )
41
- end
27
+ def session_key
28
+ srp_verifier.K
29
+ end
42
30
 
43
- def public_key_bytes
44
- public_key.unpack1('H*')
45
- end
31
+ def verify_session_bytes
32
+ [verify_session].pack('H*')
33
+ end
46
34
 
47
- def device_proof_bytes
48
- device_proof.unpack1('H*')
49
- end
35
+ def verify_session
36
+ srp_verifier.verify_session(
37
+ srp_session.merge({A: public_key_bytes}),
38
+ device_proof_bytes
39
+ )
40
+ end
50
41
 
51
- def srp_verifier
52
- @_verifier ||= RubyHome::SRP::Verifier.new
53
- end
42
+ def srp_verifier
43
+ @_verifier ||= RubyHome::SRP::Verifier.new
44
+ end
54
45
 
55
- attr_reader :public_key, :device_proof, :srp_session
46
+ attr_reader :public_key_bytes, :device_proof_bytes, :srp_session
56
47
  end
57
48
  end
@@ -1,3 +1,3 @@
1
1
  module RubyHome
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
data/rubyhome.gemspec CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency 'dnssd', '~> 3.0'
31
31
  spec.add_dependency 'facets', '~> 3.1'
32
32
  spec.add_dependency 'hkdf', '~> 0.3.0'
33
- spec.add_dependency 'oj', '3.7.9'
33
+ spec.add_dependency 'oj', '3.7.12'
34
34
  spec.add_dependency 'rbnacl', '~> 6.0'
35
35
  spec.add_dependency 'ruby_home-srp', '~> 1.3'
36
36
  spec.add_dependency 'ruby_home-tlv', '~> 0.1.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_home
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karl Entwistle
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-13 00:00:00.000000000 Z
11
+ date: 2019-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bindata
@@ -78,14 +78,14 @@ dependencies:
78
78
  requirements:
79
79
  - - '='
80
80
  - !ruby/object:Gem::Version
81
- version: 3.7.9
81
+ version: 3.7.12
82
82
  type: :runtime
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - '='
87
87
  - !ruby/object:Gem::Version
88
- version: 3.7.9
88
+ version: 3.7.12
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: rbnacl
91
91
  requirement: !ruby/object:Gem::Requirement
@@ -262,6 +262,7 @@ files:
262
262
  - lib/ruby_home/device_id.rb
263
263
  - lib/ruby_home/dns/service.rb
264
264
  - lib/ruby_home/dns/text_record.rb
265
+ - lib/ruby_home/errors.rb
265
266
  - lib/ruby_home/factories/characteristic_factory.rb
266
267
  - lib/ruby_home/factories/service_factory.rb
267
268
  - lib/ruby_home/factories/templates/characteristic_template.rb
@@ -304,6 +305,7 @@ files:
304
305
  - lib/ruby_home/http/serializers/uuid_helper.rb
305
306
  - lib/ruby_home/http/services/session_notifier.rb
306
307
  - lib/ruby_home/http/services/start_srp_service.rb
308
+ - lib/ruby_home/http/services/verify_finish_service.rb
307
309
  - lib/ruby_home/http/services/verify_srp_service.rb
308
310
  - lib/ruby_home/identifier_cache.rb
309
311
  - lib/ruby_home/password.rb