ruby_home 0.1.14 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ruby_home/hap/ev_response.rb +14 -21
- data/lib/ruby_home/hap/hap_request.rb +2 -17
- data/lib/ruby_home/hap/hap_response.rb +0 -17
- data/lib/ruby_home/hap/server.rb +3 -3
- data/lib/ruby_home/hap/{http_decryption.rb → session/decrypter.rb} +3 -3
- data/lib/ruby_home/hap/session/encrypter.rb +56 -0
- data/lib/ruby_home/hap/session.rb +55 -38
- data/lib/ruby_home/version.rb +1 -1
- metadata +4 -4
- data/lib/ruby_home/hap/http_encryption.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90d257a9cc88bba2f6323a89829fc89000e6e84842dbf7abadefb35168eb2848
|
4
|
+
data.tar.gz: 94acb47192d8cb7b9a54f01f7621da8b5371c2218ebf9494d2324af2193a705d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e229661aca3237368c77159703e01b10ad8a39d4c3ce35176ce73251668bba6077646285c2360fa783d79d5c77b658ae84299af6143ecd613b8abf97edd2213b
|
7
|
+
data.tar.gz: 3e4aadce797eb3b8a8be1ae6f70af601866726c7d53f76e3a0c7246fda25affadc0c67220e98d1596b4befa1a6dc6299ff89f7863c232b45e1748529497d84c8
|
@@ -3,44 +3,37 @@ module RubyHome
|
|
3
3
|
class EVResponse
|
4
4
|
def initialize(session, body)
|
5
5
|
@session = session
|
6
|
-
@socket = session.socket
|
7
6
|
@body = body
|
8
7
|
end
|
9
8
|
|
10
9
|
def send_response
|
11
|
-
|
12
|
-
|
13
|
-
send_header(response)
|
14
|
-
send_body(response)
|
15
|
-
|
16
|
-
encrypter = session.encrypter
|
17
|
-
encrypted_response = encrypter.encrypt(response).join
|
18
|
-
session.accessory_to_controller_count = encrypter.count
|
19
|
-
|
20
|
-
socket << encrypted_response
|
10
|
+
send_header(session)
|
11
|
+
send_body(session)
|
21
12
|
end
|
22
13
|
|
23
14
|
private
|
24
15
|
|
25
|
-
attr_reader :body, :
|
16
|
+
attr_reader :body, :session
|
26
17
|
|
27
18
|
CRLF = -"\x0d\x0a"
|
28
19
|
STATUS_LINE = -'EVENT/1.0 200 OK'
|
29
20
|
CONTENT_TYPE_LINE = -'Content-Type: application/hap+json'
|
30
21
|
|
31
|
-
def
|
32
|
-
|
33
|
-
socket << CONTENT_TYPE_LINE + CRLF
|
34
|
-
socket << content_length_line + CRLF
|
35
|
-
socket << CRLF
|
22
|
+
def content_length_line
|
23
|
+
"Content-Length: #{body.length}"
|
36
24
|
end
|
37
25
|
|
38
|
-
def
|
39
|
-
|
26
|
+
def send_header(io)
|
27
|
+
data = STATUS_LINE + CRLF
|
28
|
+
data << CONTENT_TYPE_LINE + CRLF
|
29
|
+
data << content_length_line + CRLF
|
30
|
+
data << CRLF
|
31
|
+
|
32
|
+
io.write(data)
|
40
33
|
end
|
41
34
|
|
42
|
-
def
|
43
|
-
|
35
|
+
def send_body(io)
|
36
|
+
io.write(body)
|
44
37
|
end
|
45
38
|
end
|
46
39
|
end
|
@@ -1,26 +1,11 @@
|
|
1
1
|
module RubyHome
|
2
2
|
module HAP
|
3
3
|
class HAPRequest < WEBrick::HTTPRequest
|
4
|
-
|
5
|
-
@session = session
|
6
|
-
socket = session.socket
|
7
|
-
|
8
|
-
if session.decryption_time?
|
9
|
-
request_line = socket.read_nonblock(@buffer_size)
|
10
|
-
|
11
|
-
decrypter = session.decrypter
|
12
|
-
decrypted_request = decrypter.decrypt(request_line).join
|
13
|
-
session.controller_to_accessory_count = decrypter.count
|
14
|
-
|
15
|
-
super(StringIO.new(decrypted_request))
|
16
|
-
else
|
17
|
-
super(socket)
|
18
|
-
end
|
19
|
-
end
|
4
|
+
attr_accessor :session
|
20
5
|
|
21
6
|
def meta_vars
|
22
7
|
super.merge(
|
23
|
-
{ "REQUEST_SESSION" =>
|
8
|
+
{ "REQUEST_SESSION" => session }
|
24
9
|
)
|
25
10
|
end
|
26
11
|
end
|
@@ -1,23 +1,6 @@
|
|
1
1
|
module RubyHome
|
2
2
|
module HAP
|
3
3
|
class HAPResponse < WEBrick::HTTPResponse
|
4
|
-
def send_response(session)
|
5
|
-
socket = session.socket
|
6
|
-
|
7
|
-
if session.encryption_time?
|
8
|
-
response = StringIO.new
|
9
|
-
super(response)
|
10
|
-
|
11
|
-
encrypter = session.encrypter
|
12
|
-
|
13
|
-
encrypted_response = encrypter.encrypt(response.string).join
|
14
|
-
session.accessory_to_controller_count = encrypter.count
|
15
|
-
|
16
|
-
_write_data(socket, encrypted_response)
|
17
|
-
else
|
18
|
-
super(socket)
|
19
|
-
end
|
20
|
-
end
|
21
4
|
end
|
22
5
|
end
|
23
6
|
end
|
data/lib/ruby_home/hap/server.rb
CHANGED
@@ -42,13 +42,13 @@ module RubyHome
|
|
42
42
|
def read(socket)
|
43
43
|
return close(socket) if socket.eof?
|
44
44
|
|
45
|
-
session = SESSIONS[socket] ||= Session.new(socket)
|
46
|
-
|
47
45
|
request = HAPRequest.new(webrick_config)
|
48
46
|
response = HAPResponse.new(webrick_config)
|
49
47
|
|
50
|
-
|
48
|
+
session = SESSIONS[socket] ||= Session.new(socket)
|
49
|
+
request.session = session
|
51
50
|
|
51
|
+
request.parse(session.parse)
|
52
52
|
response.request_method = request.request_method
|
53
53
|
response.request_uri = request.request_uri
|
54
54
|
response.request_http_version = request.http_version
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RubyHome
|
2
2
|
module HAP
|
3
|
-
class
|
3
|
+
class Decrypter
|
4
4
|
AAD_LENGTH_BYTES = 2.freeze
|
5
5
|
AUTHENTICATE_TAG_LENGTH_BYTES = 16.freeze
|
6
6
|
NONCE_32_BIT_FIX_COMMENT_PART = [0].pack('L').freeze
|
@@ -16,7 +16,7 @@ module RubyHome
|
|
16
16
|
|
17
17
|
while read_pointer < data.length
|
18
18
|
little_endian_length_of_encrypted_data = data[read_pointer...read_pointer+AAD_LENGTH_BYTES]
|
19
|
-
length_of_encrypted_data = little_endian_length_of_encrypted_data.
|
19
|
+
length_of_encrypted_data = little_endian_length_of_encrypted_data.unpack1('v')
|
20
20
|
read_pointer += AAD_LENGTH_BYTES
|
21
21
|
|
22
22
|
message = data[read_pointer...read_pointer+length_of_encrypted_data]
|
@@ -32,7 +32,7 @@ module RubyHome
|
|
32
32
|
increment_count!
|
33
33
|
end
|
34
34
|
|
35
|
-
decrypted_data
|
35
|
+
decrypted_data.join
|
36
36
|
end
|
37
37
|
|
38
38
|
attr_reader :count
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module RubyHome
|
2
|
+
module HAP
|
3
|
+
class Session
|
4
|
+
class Encrypter
|
5
|
+
MAX_FRAME_LENGTH = 1024.freeze
|
6
|
+
NONCE_32_BIT_FIX_COMMENT_PART = [0].pack('L').freeze
|
7
|
+
|
8
|
+
def initialize(key, count: 0)
|
9
|
+
@key = key
|
10
|
+
@count = count
|
11
|
+
end
|
12
|
+
|
13
|
+
def encrypt(data)
|
14
|
+
encrypted_data = []
|
15
|
+
read_pointer = 0
|
16
|
+
|
17
|
+
while read_pointer < data.length
|
18
|
+
encrypted_frame = ""
|
19
|
+
|
20
|
+
frame = data[read_pointer...read_pointer+MAX_FRAME_LENGTH]
|
21
|
+
length_of_encrypted_data = frame.length
|
22
|
+
little_endian_length_of_encrypted_data = [length_of_encrypted_data].pack('v')
|
23
|
+
|
24
|
+
encrypted_frame += little_endian_length_of_encrypted_data
|
25
|
+
encrypted_frame += chacha20poly1305ietf.encrypt(nonce, frame, little_endian_length_of_encrypted_data)
|
26
|
+
encrypted_data << encrypted_frame
|
27
|
+
|
28
|
+
read_pointer += length_of_encrypted_data
|
29
|
+
increment_count!
|
30
|
+
end
|
31
|
+
|
32
|
+
encrypted_data.join
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :count
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :key
|
40
|
+
|
41
|
+
def increment_count!
|
42
|
+
@count += 1
|
43
|
+
end
|
44
|
+
|
45
|
+
def nonce
|
46
|
+
NONCE_32_BIT_FIX_COMMENT_PART + [count].pack('Q')
|
47
|
+
end
|
48
|
+
|
49
|
+
def chacha20poly1305ietf
|
50
|
+
@_chacha20poly1305ietf ||= HAP::Crypto::ChaCha20Poly1305.new(key)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -1,68 +1,85 @@
|
|
1
1
|
module RubyHome
|
2
2
|
module HAP
|
3
3
|
class Session
|
4
|
-
|
5
|
-
@socket = socket
|
6
|
-
@accessory_to_controller_count = 0
|
7
|
-
@controller_to_accessory_count = 0
|
8
|
-
end
|
4
|
+
PARSE_BUFFER_SIZE = 65536
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
attr_writer :controller_to_accessory_count
|
15
|
-
attr_accessor :shared_secret
|
16
|
-
attr_accessor :session_key
|
17
|
-
attr_accessor :srp_session
|
18
|
-
|
19
|
-
def encryption_time?
|
20
|
-
accessory_to_controller_key? && received_encrypted_request?
|
6
|
+
def initialize(socket, decrypter_class: Decrypter, encrypter_class: Encrypter)
|
7
|
+
@socket = socket
|
8
|
+
@encrypter_class = encrypter_class
|
9
|
+
@decrypter_class = decrypter_class
|
21
10
|
end
|
22
11
|
|
23
|
-
|
24
|
-
|
25
|
-
|
12
|
+
attr_accessor(
|
13
|
+
:controller_to_accessory_key,
|
14
|
+
:accessory_to_controller_key,
|
15
|
+
:shared_secret,
|
16
|
+
:session_key,
|
17
|
+
:srp_session
|
18
|
+
)
|
26
19
|
|
27
|
-
def
|
28
|
-
|
20
|
+
def sufficient_privileges?
|
21
|
+
controller_to_accessory_key? && accessory_to_controller_key?
|
29
22
|
end
|
30
23
|
|
31
|
-
def
|
32
|
-
|
24
|
+
def active?
|
25
|
+
!socket.closed?
|
33
26
|
end
|
34
27
|
|
35
|
-
def
|
36
|
-
|
28
|
+
def write(data)
|
29
|
+
if encryption_time?
|
30
|
+
socket.write(encrypter.encrypt(data))
|
31
|
+
else
|
32
|
+
socket.write(data)
|
33
|
+
end
|
37
34
|
end
|
38
35
|
|
39
|
-
def
|
40
|
-
|
36
|
+
def parse
|
37
|
+
if decryption_time?
|
38
|
+
received_encrypted_request!
|
39
|
+
StringIO.new(
|
40
|
+
decrypter.decrypt(
|
41
|
+
socket.read_nonblock(PARSE_BUFFER_SIZE)
|
42
|
+
)
|
43
|
+
)
|
44
|
+
else
|
45
|
+
socket
|
46
|
+
end
|
41
47
|
end
|
42
48
|
|
43
|
-
def
|
44
|
-
|
49
|
+
def received_encrypted_request!
|
50
|
+
@received_encrypted_request ||= true
|
45
51
|
end
|
46
52
|
|
47
53
|
private
|
48
54
|
|
49
|
-
attr_reader :
|
50
|
-
:controller_to_accessory_count
|
55
|
+
attr_reader :socket, :encrypter_class, :decrypter_class
|
51
56
|
|
52
|
-
def
|
53
|
-
|
57
|
+
def received_encrypted_request?
|
58
|
+
@received_encrypted_request ||= false
|
54
59
|
end
|
55
60
|
|
56
|
-
def
|
61
|
+
def encrypter
|
62
|
+
@_encrypter ||= encrypter_class.new(accessory_to_controller_key)
|
63
|
+
end
|
64
|
+
|
65
|
+
def encryption_time?
|
66
|
+
accessory_to_controller_key? && received_encrypted_request?
|
67
|
+
end
|
68
|
+
|
69
|
+
def decrypter
|
70
|
+
@_decrypter ||= decrypter_class.new(controller_to_accessory_key)
|
71
|
+
end
|
72
|
+
|
73
|
+
def decryption_time?
|
57
74
|
controller_to_accessory_key.present?
|
58
75
|
end
|
59
76
|
|
60
|
-
def
|
61
|
-
|
77
|
+
def accessory_to_controller_key?
|
78
|
+
accessory_to_controller_key.present?
|
62
79
|
end
|
63
80
|
|
64
|
-
def
|
65
|
-
|
81
|
+
def controller_to_accessory_key?
|
82
|
+
controller_to_accessory_key.present?
|
66
83
|
end
|
67
84
|
end
|
68
85
|
end
|
data/lib/ruby_home/version.rb
CHANGED
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.1.
|
4
|
+
version: 0.1.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Entwistle
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -291,11 +291,11 @@ files:
|
|
291
291
|
- lib/ruby_home/hap/ev_response.rb
|
292
292
|
- lib/ruby_home/hap/hap_request.rb
|
293
293
|
- lib/ruby_home/hap/hap_response.rb
|
294
|
-
- lib/ruby_home/hap/http_decryption.rb
|
295
|
-
- lib/ruby_home/hap/http_encryption.rb
|
296
294
|
- lib/ruby_home/hap/server.rb
|
297
295
|
- lib/ruby_home/hap/service.rb
|
298
296
|
- lib/ruby_home/hap/session.rb
|
297
|
+
- lib/ruby_home/hap/session/decrypter.rb
|
298
|
+
- lib/ruby_home/hap/session/encrypter.rb
|
299
299
|
- lib/ruby_home/hap/tlv.rb
|
300
300
|
- lib/ruby_home/hap/values/base_value.rb
|
301
301
|
- lib/ruby_home/hap/values/bool_value.rb
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module RubyHome
|
2
|
-
module HAP
|
3
|
-
class HTTPEncryption
|
4
|
-
MAX_FRAME_LENGTH = 1024.freeze
|
5
|
-
NONCE_32_BIT_FIX_COMMENT_PART = [0].pack('L').freeze
|
6
|
-
|
7
|
-
def initialize(key, count: 0)
|
8
|
-
@key = key
|
9
|
-
@count = count
|
10
|
-
end
|
11
|
-
|
12
|
-
def encrypt(data)
|
13
|
-
encrypted_data = []
|
14
|
-
read_pointer = 0
|
15
|
-
|
16
|
-
while read_pointer < data.length
|
17
|
-
encrypted_frame = ""
|
18
|
-
|
19
|
-
frame = data[read_pointer...read_pointer+MAX_FRAME_LENGTH]
|
20
|
-
length_of_encrypted_data = frame.length
|
21
|
-
little_endian_length_of_encrypted_data = [length_of_encrypted_data].pack('v')
|
22
|
-
|
23
|
-
encrypted_frame += little_endian_length_of_encrypted_data
|
24
|
-
encrypted_frame += chacha20poly1305ietf.encrypt(nonce, frame, little_endian_length_of_encrypted_data)
|
25
|
-
encrypted_data << encrypted_frame
|
26
|
-
|
27
|
-
read_pointer += length_of_encrypted_data
|
28
|
-
increment_count!
|
29
|
-
end
|
30
|
-
|
31
|
-
encrypted_data
|
32
|
-
end
|
33
|
-
|
34
|
-
attr_reader :count
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
attr_reader :key
|
39
|
-
|
40
|
-
def increment_count!
|
41
|
-
@count += 1
|
42
|
-
end
|
43
|
-
|
44
|
-
def nonce
|
45
|
-
NONCE_32_BIT_FIX_COMMENT_PART + [count].pack('Q')
|
46
|
-
end
|
47
|
-
|
48
|
-
def chacha20poly1305ietf
|
49
|
-
@_chacha20poly1305ietf ||= HAP::Crypto::ChaCha20Poly1305.new(key)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|