boat 0.2 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/boat.gemspec +2 -0
- data/lib/boat/client.rb +11 -10
- data/lib/boat/server.rb +11 -14
- data/lib/boat/version.rb +1 -1
- data/server.conf +1 -1
- metadata +18 -4
data/boat.gemspec
CHANGED
data/lib/boat/client.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'openssl'
|
2
2
|
require 'socket'
|
3
3
|
|
4
4
|
class Boat::Client
|
@@ -21,7 +21,7 @@ class Boat::Client
|
|
21
21
|
raise Error, response unless response =~ /^251 HMAC-SHA256 (.+)/
|
22
22
|
|
23
23
|
puts "[debug] sending password" if @debug
|
24
|
-
password_hash = HMAC
|
24
|
+
password_hash = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), key, $1)
|
25
25
|
socket_puts "pass #{password_hash}"
|
26
26
|
response = socket_gets.to_s
|
27
27
|
raise Error, response unless response =~ /^250/
|
@@ -37,16 +37,17 @@ class Boat::Client
|
|
37
37
|
|
38
38
|
size ||= io.respond_to?(:stat) ? io.stat.size : io.length
|
39
39
|
|
40
|
+
digest = OpenSSL::Digest.new('sha256')
|
40
41
|
hash ||= if io.respond_to?(:path)
|
41
|
-
|
42
|
+
digest.file(io.path).hexdigest
|
42
43
|
elsif !io.respond_to?(:read)
|
43
|
-
|
44
|
+
digest.hexdigest(io)
|
44
45
|
else
|
45
46
|
"-"
|
46
47
|
end
|
47
48
|
|
48
|
-
client_salt = [
|
49
|
-
signature = HMAC
|
49
|
+
client_salt = [digest.digest((0..64).inject("") {|r, i| r << rand(256).chr})].pack("m").strip
|
50
|
+
signature = OpenSSL::HMAC.hexdigest(digest, @key, "#{server_salt}#{encoded_filename}#{size}#{hash}#{client_salt}")
|
50
51
|
|
51
52
|
puts "[debug] sending data command" if @debug
|
52
53
|
socket_puts "data #{size} #{hash} #{client_salt} #{signature}"
|
@@ -54,7 +55,7 @@ class Boat::Client
|
|
54
55
|
|
55
56
|
# The server might already have the file with this hash - if so it'll return 255 at this point.
|
56
57
|
if matches = response.strip.match(/\A255 accepted ([0-9a-f]{64})\z/i)
|
57
|
-
confirm_hash = HMAC
|
58
|
+
confirm_hash = OpenSSL::HMAC.hexdigest(digest, @key, "#{client_salt}#{hash}")
|
58
59
|
if matches[1] != confirm_hash
|
59
60
|
raise Error, "Incorrect server signature; the srver may be faking that it received the upload"
|
60
61
|
end
|
@@ -64,7 +65,7 @@ class Boat::Client
|
|
64
65
|
raise Error, response unless response =~ /^253/
|
65
66
|
|
66
67
|
if io.respond_to?(:read)
|
67
|
-
digest = Digest
|
68
|
+
digest = OpenSSL::Digest.new('sha256') if hash == '-'
|
68
69
|
written = 0
|
69
70
|
while data = io.read(@chunk_size)
|
70
71
|
if @debug
|
@@ -86,7 +87,7 @@ class Boat::Client
|
|
86
87
|
|
87
88
|
if response =~ /^254/ # we need to send the hash of the file because we didn't on the DATA line
|
88
89
|
hash = digest.to_s
|
89
|
-
signature = HMAC
|
90
|
+
signature = OpenSSL::HMAC.hexdigest(digest, @key, "#{server_salt}#{encoded_filename}#{size}#{hash}#{client_salt}")
|
90
91
|
|
91
92
|
puts "[debug] sending confirm command" if @debug
|
92
93
|
socket_puts "confirm #{hash} #{signature}\n"
|
@@ -95,7 +96,7 @@ class Boat::Client
|
|
95
96
|
|
96
97
|
raise Error, response unless response && matches = response.strip.match(/\A255 accepted ([0-9a-f]{64})\z/i)
|
97
98
|
|
98
|
-
confirm_hash = HMAC
|
99
|
+
confirm_hash = OpenSSL::HMAC.hexdigest(digest, @key, "#{client_salt}#{hash}")
|
99
100
|
if matches[1] != confirm_hash
|
100
101
|
raise Error, "Incorrect server signature; the srver may be faking that it received the upload"
|
101
102
|
end
|
data/lib/boat/server.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
require '
|
1
|
+
require 'openssl'
|
2
2
|
require 'eventmachine'
|
3
|
-
require 'syslog'
|
4
|
-
require 'digest'
|
5
3
|
require 'fileutils'
|
6
4
|
|
7
5
|
class Boat::Server
|
@@ -22,6 +20,7 @@ class Boat::Server
|
|
22
20
|
@@last_connection_id += 1
|
23
21
|
@connection_id = @@last_connection_id
|
24
22
|
@temporary_files = []
|
23
|
+
@digest = OpenSSL::Digest::Digest.new('sha256')
|
25
24
|
send_data "220 Boat Server #{Boat::VERSION}\n"
|
26
25
|
end
|
27
26
|
|
@@ -59,7 +58,7 @@ class Boat::Server
|
|
59
58
|
send_data "500 USER first\n"
|
60
59
|
else
|
61
60
|
user = @configuration.fetch("users", {}).fetch(@username, nil)
|
62
|
-
expected = HMAC
|
61
|
+
expected = OpenSSL::HMAC.hexdigest(@digest, user["key"], @login_salt) if user
|
63
62
|
if user && expected && args == expected
|
64
63
|
send_data "250 OK\n"
|
65
64
|
@user = user
|
@@ -107,10 +106,10 @@ class Boat::Server
|
|
107
106
|
|
108
107
|
if size >= 1<<31
|
109
108
|
send_data "500 size too large\n"
|
110
|
-
elsif signature != HMAC
|
109
|
+
elsif signature != OpenSSL::HMAC.hexdigest(@digest, @user["key"], "#{@put.fetch(:server_salt)}#{@put.fetch(:filename)}#{size}#{file_hash}#{client_salt}")
|
111
110
|
send_data "500 signature is invalid\n"
|
112
|
-
elsif File.exists?(current_filename = "#{repository_path}/current.#{@put.fetch(:filename)}") && Digest
|
113
|
-
signature = HMAC
|
111
|
+
elsif File.exists?(current_filename = "#{repository_path}/current.#{@put.fetch(:filename)}") && OpenSSL::Digest.new('sha256').file(current_filename).to_s == file_hash
|
112
|
+
signature = OpenSSL::HMAC.hexdigest(@digest, @user["key"], "#{client_salt}#{file_hash}")
|
114
113
|
send_data "255 accepted #{signature}\n"
|
115
114
|
else
|
116
115
|
@put[:temporary_id] = "#{Time.now.to_i}.#{Process.pid}.#{@connection_id}"
|
@@ -121,7 +120,7 @@ class Boat::Server
|
|
121
120
|
:hash => (file_hash unless file_hash == '-'),
|
122
121
|
:client_salt => client_salt,
|
123
122
|
:file_handle => File.open(@put[:temporary_filename], "w"),
|
124
|
-
:digest => Digest
|
123
|
+
:digest => OpenSSL::Digest.new('sha256'))
|
125
124
|
|
126
125
|
@temporary_files << @put[:temporary_filename]
|
127
126
|
|
@@ -156,7 +155,7 @@ class Boat::Server
|
|
156
155
|
file_hash = matches[1].downcase
|
157
156
|
signature = matches[2].downcase
|
158
157
|
|
159
|
-
if signature != HMAC
|
158
|
+
if signature != OpenSSL::HMAC.hexdigest(@digest, @user["key"], "#{@put.fetch(:server_salt)}#{@put.fetch(:filename)}#{@put.fetch(:size)}#{file_hash}#{@put.fetch(:client_salt)}")
|
160
159
|
send_data "500 signature is invalid\n"
|
161
160
|
@put = nil
|
162
161
|
else
|
@@ -167,7 +166,7 @@ class Boat::Server
|
|
167
166
|
end
|
168
167
|
|
169
168
|
def complete_put
|
170
|
-
calculated_hash = @put.fetch(:digest).
|
169
|
+
calculated_hash = @put.fetch(:digest).hexdigest
|
171
170
|
|
172
171
|
if @put.fetch(:hash) != calculated_hash
|
173
172
|
send_data "500 file hash does not match hash supplied by client\n"
|
@@ -195,7 +194,7 @@ class Boat::Server
|
|
195
194
|
end
|
196
195
|
File.symlink(version_filename, symlink_name)
|
197
196
|
|
198
|
-
signature = HMAC
|
197
|
+
signature = OpenSSL::HMAC.hexdigest(@digest, @user["key"], "#{@put.fetch(:client_salt)}#{@put.fetch(:hash)}")
|
199
198
|
send_data "255 accepted #{signature}\n"
|
200
199
|
ensure
|
201
200
|
@put = nil
|
@@ -228,7 +227,7 @@ class Boat::Server
|
|
228
227
|
end
|
229
228
|
|
230
229
|
def random_salt
|
231
|
-
[Digest
|
230
|
+
[OpenSSL::Digest.new('sha256').digest((0..64).inject("") {|r, i| r << rand(256).chr})].pack("m").strip
|
232
231
|
end
|
233
232
|
|
234
233
|
def repository_path
|
@@ -277,8 +276,6 @@ class Boat::Server
|
|
277
276
|
end
|
278
277
|
end
|
279
278
|
|
280
|
-
#Syslog.open 'boat'
|
281
|
-
|
282
279
|
File.umask(0077)
|
283
280
|
EventMachine.run do
|
284
281
|
EventMachine.start_server(
|
data/lib/boat/version.rb
CHANGED
data/server.conf
CHANGED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: boat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Roger Nesbitt
|
@@ -16,8 +17,21 @@ cert_chain: []
|
|
16
17
|
|
17
18
|
date: 2011-05-30 00:00:00 +12:00
|
18
19
|
default_executable:
|
19
|
-
dependencies:
|
20
|
-
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: eventmachine
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
21
35
|
description: File upload client and server specifically aimed at transferring already-encrypted backups
|
22
36
|
email: []
|
23
37
|
|