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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
# File 'lib/boat/client.rb', line 30
def put(io, filename, size = nil, hash = nil)
encoded_filename = CGI.escape(filename)
puts "[debug] sending put command with filename #{encoded_filename}" if @debug
socket_puts "put #{encoded_filename}"
response = socket_gets.to_s
raise Error, response unless response =~ /^250/
server_salt = response.strip[4..-1]
size ||= io.respond_to?(:stat) ? io.stat.size : io.length
digest = OpenSSL::Digest.new('sha256')
hash ||= if io.respond_to?(:path) && io.path
digest.file(io.path).hexdigest
elsif !io.respond_to?(:read)
digest.hexdigest(io)
else
"-"
end
client_salt = [digest.digest((0..64).inject("") {|r, i| r << rand(256).chr})].pack("m").strip
signature = OpenSSL::HMAC.hexdigest(digest, @key, "#{server_salt}#{encoded_filename}#{size}#{hash}#{client_salt}")
puts "[debug] sending data command" if @debug
socket_puts "data #{size} #{hash} #{client_salt} #{signature}"
response = socket_gets.to_s
if matches = response.strip.match(/\A255 accepted ([0-9a-f]{64})\z/i)
confirm_hash = OpenSSL::HMAC.hexdigest(digest, @key, "#{client_salt}#{hash}")
if matches[1] != confirm_hash
raise Error, "Incorrect server signature; the srver may be faking that it received the upload"
end
return size
end
raise Error, response unless response =~ /^253/
if io.respond_to?(:read)
digest = OpenSSL::Digest.new('sha256') if hash == '-'
written = 0
while data = io.read(@chunk_size)
if @debug
print "[debug] sending data (#{written} / #{size} bytes)\r"
STDOUT.flush
end
digest << data if hash == '-'
@socket.write(data)
written += data.length
end
else
puts "[debug] sending data" if @debug
@socket.write(io)
digest << io
end
puts "[debug] data sent (#{size} bytes); waiting for response" if @debug
response = socket_gets.to_s
if response =~ /^254/ hash = digest.to_s
signature = OpenSSL::HMAC.hexdigest(digest, @key, "#{server_salt}#{encoded_filename}#{size}#{hash}#{client_salt}")
puts "[debug] sending confirm command" if @debug
socket_puts "confirm #{hash} #{signature}\n"
response = socket_gets.to_s
end
raise Error, response unless response && matches = response.strip.match(/\A255 accepted ([0-9a-f]{64})\z/i)
confirm_hash = OpenSSL::HMAC.hexdigest(digest, @key, "#{client_salt}#{hash}")
if matches[1] != confirm_hash
raise Error, "Incorrect server signature; the srver may be faking that it received the upload"
end
size
end
|