ruby_smb 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -4
- data/.travis.yml +3 -5
- data/Gemfile +6 -2
- data/examples/negotiate.rb +51 -8
- data/examples/read_file_encryption.rb +56 -0
- data/lib/ruby_smb.rb +4 -0
- data/lib/ruby_smb/client.rb +172 -16
- data/lib/ruby_smb/client/authentication.rb +27 -8
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +133 -12
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +4 -4
- data/lib/ruby_smb/client/utils.rb +8 -7
- data/lib/ruby_smb/crypto.rb +30 -0
- data/lib/ruby_smb/dispatcher/socket.rb +2 -2
- data/lib/ruby_smb/error.rb +28 -1
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +4 -4
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
- data/lib/ruby_smb/smb1/pipe.rb +2 -2
- data/lib/ruby_smb/smb1/tree.rb +3 -3
- data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
- data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
- data/lib/ruby_smb/smb2/file.rb +25 -43
- data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
- data/lib/ruby_smb/smb2/packet.rb +2 -0
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +49 -3
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
- data/lib/ruby_smb/smb2/pipe.rb +3 -16
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +23 -17
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +3 -1
- data/spec/lib/ruby_smb/client_spec.rb +1256 -57
- data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
- data/spec/lib/ruby_smb/error_spec.rb +59 -0
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
- data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +86 -62
- data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
- data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
- data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
- data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
- data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +0 -40
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +53 -8
- metadata +124 -75
- metadata.gz.sig +0 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe RubySMB::Crypto::KDF do
|
4
|
+
describe '.counter_mode' do
|
5
|
+
it 'generates the expected 128-bit key' do
|
6
|
+
expected_key = "\x3c\x5e\x0a\x1b\x0a\xce\xa5\xb2\x64\x3f\xab\x78\xdc\x82\x31\x3b".b
|
7
|
+
expect(described_class.counter_mode('ki', 'label', 'context')).to eq(expected_key)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'generates the expected 256-bit key' do
|
11
|
+
expected_key =
|
12
|
+
"\x33\x4d\xa9\x6d\x24\x7e\xcb\x14\xf6\x24\x00\x97\x26\x51\xd5\xb4"\
|
13
|
+
"\x54\x5f\xda\x95\xf0\x5a\xcb\x25\x92\x57\xae\x71\x1c\x37\x20\x5b".b
|
14
|
+
expect(described_class.counter_mode('ki', 'label', 'context', length: 256)).to eq(expected_key)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'raises the expected exception when an error occurs' do
|
18
|
+
allow(OpenSSL::Digest).to receive(:new).and_raise(OpenSSL::OpenSSLError)
|
19
|
+
expect { described_class.counter_mode('ki', 'label', 'context') }.to raise_error(
|
20
|
+
RubySMB::Error::EncryptionError,
|
21
|
+
"Crypto::KDF.counter_mode OpenSSL error: OpenSSL::OpenSSLError"
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe RubySMB::Error::InvalidPacket do
|
4
|
+
context 'with a String' do
|
5
|
+
it 'outputs the expected error message' do
|
6
|
+
ex = described_class.new('My exception')
|
7
|
+
expect(ex.to_s).to eq('My exception')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with a Hash' do
|
12
|
+
it 'outputs the expected error message' do
|
13
|
+
ex = described_class.new(
|
14
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
15
|
+
expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
|
16
|
+
expected_custom: "extended_security=1",
|
17
|
+
received_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
18
|
+
received_cmd: RubySMB::SMB2::Packet::NegotiateResponse::COMMAND,
|
19
|
+
received_custom: "extended_security=0"
|
20
|
+
)
|
21
|
+
expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got SMB2 protocol with command=0 (extended_security=0)')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with an unsupported type' do
|
26
|
+
it 'raises the expected exception' do
|
27
|
+
expect { described_class.new(['wrong']) }.to raise_error(
|
28
|
+
ArgumentError,
|
29
|
+
'InvalidPacket expects a String or a Hash, got a Array'
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
RSpec.describe RubySMB::Error::UnexpectedStatusCode do
|
37
|
+
context 'with a WindowsError::ErrorCode' do
|
38
|
+
it 'outputs the expected error message' do
|
39
|
+
ex = described_class.new(WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW)
|
40
|
+
expect(ex.to_s).to eq('The server responded with an unexpected status code: STATUS_BUFFER_OVERFLOW')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with an Integer' do
|
45
|
+
it 'outputs the expected error message' do
|
46
|
+
ex = described_class.new(0x80000005)
|
47
|
+
expect(ex.to_s).to eq('The server responded with an unexpected status code: STATUS_BUFFER_OVERFLOW')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'with an unsupported type' do
|
52
|
+
it 'raises the expected exception' do
|
53
|
+
expect { described_class.new(['wrong']) }.to raise_error(
|
54
|
+
ArgumentError,
|
55
|
+
'Status code must be a WindowsError::ErrorCode or an Integer, got Array'
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupLegacyRequest do
|
|
10
10
|
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
11
11
|
end
|
12
12
|
|
13
|
-
it 'should have the command set to
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
13
|
+
it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should not have the response flag set' do
|
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupLegacyResponse do
|
|
10
10
|
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
11
11
|
end
|
12
12
|
|
13
|
-
it 'should have the command set to
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
13
|
+
it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should have the response flag set' do
|
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupRequest do
|
|
10
10
|
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
11
11
|
end
|
12
12
|
|
13
|
-
it 'should have the command set to
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
13
|
+
it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should not have the response flag set' do
|
@@ -11,7 +11,7 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupResponse do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'should have the command set to SMB_COM_NEGOTIATE' do
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should have the response flag set' do
|
@@ -5,6 +5,7 @@ RSpec.describe RubySMB::SMB2::BitField::SessionFlags do
|
|
5
5
|
|
6
6
|
it { is_expected.to respond_to :guest }
|
7
7
|
it { is_expected.to respond_to :null }
|
8
|
+
it { is_expected.to respond_to :encrypt_data }
|
8
9
|
|
9
10
|
it 'is little endian' do
|
10
11
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
@@ -25,4 +26,12 @@ RSpec.describe RubySMB::SMB2::BitField::SessionFlags do
|
|
25
26
|
|
26
27
|
it_behaves_like 'bit field with one flag set', :null, 'v', 0x00000002
|
27
28
|
end
|
29
|
+
|
30
|
+
describe '#encrypt_data' do
|
31
|
+
it 'should be a 1-bit field per the SMB spec' do
|
32
|
+
expect(flags.encrypt_data).to be_a BinData::Bit1
|
33
|
+
end
|
34
|
+
|
35
|
+
it_behaves_like 'bit field with one flag set', :encrypt_data, 'v', 0x00000004
|
36
|
+
end
|
28
37
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
RSpec.describe RubySMB::SMB2::BitField::ShareFlags do
|
2
2
|
subject(:flags) { described_class.new }
|
3
3
|
|
4
|
+
it { is_expected.to respond_to :vdo_caching }
|
5
|
+
it { is_expected.to respond_to :auto_caching }
|
4
6
|
it { is_expected.to respond_to :dfs_root }
|
5
7
|
it { is_expected.to respond_to :dfs }
|
6
8
|
it { is_expected.to respond_to :encrypt }
|
@@ -11,11 +13,28 @@ RSpec.describe RubySMB::SMB2::BitField::ShareFlags do
|
|
11
13
|
it { is_expected.to respond_to :namespace_caching }
|
12
14
|
it { is_expected.to respond_to :shared_delete }
|
13
15
|
it { is_expected.to respond_to :restrict_exclusive_opens }
|
16
|
+
it { is_expected.to respond_to :identity_remoting }
|
14
17
|
|
15
18
|
it 'is little endian' do
|
16
19
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
17
20
|
end
|
18
21
|
|
22
|
+
describe '#vdo_caching' do
|
23
|
+
it 'should be a 1-bit field per the SMB spec' do
|
24
|
+
expect(flags.vdo_caching).to be_a BinData::Bit1
|
25
|
+
end
|
26
|
+
|
27
|
+
it_behaves_like 'bit field with one flag set', :vdo_caching, 'V', 0x00000020
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#auto_caching' do
|
31
|
+
it 'should be a 1-bit field per the SMB spec' do
|
32
|
+
expect(flags.auto_caching).to be_a BinData::Bit1
|
33
|
+
end
|
34
|
+
|
35
|
+
it_behaves_like 'bit field with one flag set', :auto_caching, 'V', 0x00000010
|
36
|
+
end
|
37
|
+
|
19
38
|
describe '#dfs' do
|
20
39
|
it 'should be a 1-bit field per the SMB spec' do
|
21
40
|
expect(flags.dfs).to be_a BinData::Bit1
|
@@ -96,6 +115,14 @@ RSpec.describe RubySMB::SMB2::BitField::ShareFlags do
|
|
96
115
|
it_behaves_like 'bit field with one flag set', :encrypt, 'V', 0x00008000
|
97
116
|
end
|
98
117
|
|
118
|
+
describe '#identity_remoting' do
|
119
|
+
it 'should be a 1-bit field per the SMB spec' do
|
120
|
+
expect(flags.identity_remoting).to be_a BinData::Bit1
|
121
|
+
end
|
122
|
+
|
123
|
+
it_behaves_like 'bit field with one flag set', :identity_remoting, 'V', 0x00040000
|
124
|
+
end
|
125
|
+
|
99
126
|
describe '#set_manual_caching' do
|
100
127
|
it 'turns off the caching bits' do
|
101
128
|
flags.set_manual_caching
|
@@ -43,6 +43,7 @@ RSpec.describe RubySMB::SMB2::File do
|
|
43
43
|
it { is_expected.to respond_to :size }
|
44
44
|
it { is_expected.to respond_to :size_on_disk }
|
45
45
|
it { is_expected.to respond_to :tree }
|
46
|
+
it { is_expected.to respond_to :encryption_required }
|
46
47
|
|
47
48
|
it 'pulls the attributes from the response packet' do
|
48
49
|
expect(file.attributes).to eq create_response.file_attributes
|
@@ -52,10 +53,18 @@ RSpec.describe RubySMB::SMB2::File do
|
|
52
53
|
expect(file.guid).to eq create_response.file_id
|
53
54
|
end
|
54
55
|
|
55
|
-
it 'pulls the timestamps from the response packet' do
|
56
|
+
it 'pulls the last access timestamps from the response packet' do
|
56
57
|
expect(file.last_access).to eq create_response.last_access.to_datetime
|
57
58
|
end
|
58
59
|
|
60
|
+
it 'pulls the last change timestamps from the response packet' do
|
61
|
+
expect(file.last_change).to eq create_response.last_change.to_datetime
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'pulls the last write timestamps from the response packet' do
|
65
|
+
expect(file.last_write).to eq create_response.last_write.to_datetime
|
66
|
+
end
|
67
|
+
|
59
68
|
it 'pulls the size from the response packet' do
|
60
69
|
expect(file.size).to eq create_response.end_of_file
|
61
70
|
end
|
@@ -64,6 +73,10 @@ RSpec.describe RubySMB::SMB2::File do
|
|
64
73
|
expect(file.size_on_disk).to eq create_response.allocation_size
|
65
74
|
end
|
66
75
|
|
76
|
+
it 'sets the encryption_required flag to false by default' do
|
77
|
+
expect(file.encryption_required).to be false
|
78
|
+
end
|
79
|
+
|
67
80
|
describe '#set_header_fields' do
|
68
81
|
let(:request) { RubySMB::SMB2::Packet::ReadRequest.new }
|
69
82
|
it 'calls the set_header_field method from the Tree' do
|
@@ -113,11 +126,17 @@ RSpec.describe RubySMB::SMB2::File do
|
|
113
126
|
|
114
127
|
it 'uses a single packet to read the entire file' do
|
115
128
|
expect(file).to receive(:read_packet).with(read_length: 108, offset: 0).and_return(small_read)
|
116
|
-
expect(client).to receive(:send_recv).with(small_read).and_return 'fake data'
|
129
|
+
expect(client).to receive(:send_recv).with(small_read, encrypt: false).and_return 'fake data'
|
117
130
|
expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).with('fake data').and_return(small_response)
|
118
131
|
expect(file.read).to eq 'fake data'
|
119
132
|
end
|
120
133
|
|
134
|
+
it 'calls Client #send_recv with encryption set if required' do
|
135
|
+
file.encryption_required = true
|
136
|
+
expect(client).to receive(:send_recv).with(small_read, encrypt: true)
|
137
|
+
file.read
|
138
|
+
end
|
139
|
+
|
121
140
|
context 'when the response is not valid' do
|
122
141
|
it 'raise an InvalidPacket exception' do
|
123
142
|
small_response.smb2_header.command = RubySMB::SMB2::Commands::LOGOFF
|
@@ -155,6 +174,14 @@ RSpec.describe RubySMB::SMB2::File do
|
|
155
174
|
file.read(bytes: (described_class::MAX_PACKET_SIZE * 2))
|
156
175
|
end
|
157
176
|
|
177
|
+
it 'calls Client #send_recv with encryption set if required' do
|
178
|
+
read_request = double('Read Request')
|
179
|
+
allow(file).to receive(:read_packet).and_return(read_request)
|
180
|
+
file.encryption_required = true
|
181
|
+
expect(client).to receive(:send_recv).twice.with(read_request, encrypt: true)
|
182
|
+
file.read(bytes: (described_class::MAX_PACKET_SIZE * 2))
|
183
|
+
end
|
184
|
+
|
158
185
|
context 'when the second response is not valid' do
|
159
186
|
it 'raise an InvalidPacket exception' do
|
160
187
|
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE) do
|
@@ -204,6 +231,14 @@ RSpec.describe RubySMB::SMB2::File do
|
|
204
231
|
expect(client).to receive(:send_recv).once.and_return(write_response.to_binary_s)
|
205
232
|
file.write(data: 'test')
|
206
233
|
end
|
234
|
+
|
235
|
+
it 'calls Client #send_recv with encryption set if required' do
|
236
|
+
write_request = double('Write Request')
|
237
|
+
allow(file).to receive(:write_packet).and_return(write_request)
|
238
|
+
file.encryption_required = true
|
239
|
+
expect(client).to receive(:send_recv).once.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
|
240
|
+
file.write(data: 'test')
|
241
|
+
end
|
207
242
|
end
|
208
243
|
|
209
244
|
context 'for a large write' do
|
@@ -211,6 +246,14 @@ RSpec.describe RubySMB::SMB2::File do
|
|
211
246
|
expect(client).to receive(:send_recv).twice.and_return(write_response.to_binary_s)
|
212
247
|
file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
|
213
248
|
end
|
249
|
+
|
250
|
+
it 'calls Client #send_recv with encryption set if required' do
|
251
|
+
write_request = double('Write Request')
|
252
|
+
allow(file).to receive(:write_packet).and_return(write_request)
|
253
|
+
file.encryption_required = true
|
254
|
+
expect(client).to receive(:send_recv).twice.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
|
255
|
+
file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
|
256
|
+
end
|
214
257
|
end
|
215
258
|
|
216
259
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
@@ -248,7 +291,7 @@ RSpec.describe RubySMB::SMB2::File do
|
|
248
291
|
|
249
292
|
it 'uses a single packet to delete the entire file' do
|
250
293
|
expect(file).to receive(:delete_packet).and_return(small_delete)
|
251
|
-
expect(client).to receive(:send_recv).with(small_delete).and_return 'raw_response'
|
294
|
+
expect(client).to receive(:send_recv).with(small_delete, encrypt: false).and_return 'raw_response'
|
252
295
|
expect(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).with('raw_response').and_return(small_response)
|
253
296
|
expect(file.delete).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
254
297
|
end
|
@@ -260,6 +303,14 @@ RSpec.describe RubySMB::SMB2::File do
|
|
260
303
|
allow(small_response).to receive(:valid?).and_return(false)
|
261
304
|
expect { file.delete }.to raise_error(RubySMB::Error::InvalidPacket)
|
262
305
|
end
|
306
|
+
|
307
|
+
it 'calls Client #send_recv with encryption set if required' do
|
308
|
+
allow(file).to receive(:delete_packet)
|
309
|
+
allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
|
310
|
+
file.encryption_required = true
|
311
|
+
expect(client).to receive(:send_recv).with(small_delete, encrypt: true)
|
312
|
+
file.delete
|
313
|
+
end
|
263
314
|
end
|
264
315
|
end
|
265
316
|
|
@@ -291,11 +342,18 @@ RSpec.describe RubySMB::SMB2::File do
|
|
291
342
|
|
292
343
|
it 'uses a single packet to rename the entire file' do
|
293
344
|
expect(file).to receive(:rename_packet).and_return(small_rename)
|
294
|
-
expect(client).to receive(:send_recv).with(small_rename).and_return 'raw_response'
|
345
|
+
expect(client).to receive(:send_recv).with(small_rename, encrypt: false).and_return 'raw_response'
|
295
346
|
expect(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).with('raw_response').and_return(small_response)
|
296
347
|
expect(file.rename('new_file.txt')).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
297
348
|
end
|
298
349
|
|
350
|
+
it 'calls Client #send_recv with encryption set if required' do
|
351
|
+
allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
|
352
|
+
file.encryption_required = true
|
353
|
+
expect(client).to receive(:send_recv).with(small_rename, encrypt: true)
|
354
|
+
file.rename('new_file.txt')
|
355
|
+
end
|
356
|
+
|
299
357
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
300
358
|
allow(client).to receive(:send_recv)
|
301
359
|
allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
|
@@ -330,7 +388,13 @@ RSpec.describe RubySMB::SMB2::File do
|
|
330
388
|
end
|
331
389
|
|
332
390
|
it 'calls Client #send_recv with the expected request' do
|
333
|
-
expect(client).to receive(:send_recv).with(request)
|
391
|
+
expect(client).to receive(:send_recv).with(request, encrypt: false)
|
392
|
+
file.close
|
393
|
+
end
|
394
|
+
|
395
|
+
it 'calls Client #send_recv with encryption set if required' do
|
396
|
+
file.encryption_required = true
|
397
|
+
expect(client).to receive(:send_recv).with(request, encrypt: true)
|
334
398
|
file.close
|
335
399
|
end
|
336
400
|
|
@@ -394,7 +458,15 @@ RSpec.describe RubySMB::SMB2::File do
|
|
394
458
|
it 'calls Client #send_recv with the expected request' do
|
395
459
|
request = double('Request')
|
396
460
|
allow(file).to receive(:read_packet).and_return(request)
|
397
|
-
expect(client).to receive(:send_recv).with(request)
|
461
|
+
expect(client).to receive(:send_recv).with(request, encrypt: false)
|
462
|
+
file.send_recv_read
|
463
|
+
end
|
464
|
+
|
465
|
+
it 'calls Client #send_recv with encryption set if required' do
|
466
|
+
request = double('Request')
|
467
|
+
allow(file).to receive(:read_packet).and_return(request)
|
468
|
+
file.encryption_required = true
|
469
|
+
expect(client).to receive(:send_recv).with(request, encrypt: true)
|
398
470
|
file.send_recv_read
|
399
471
|
end
|
400
472
|
|
@@ -408,33 +480,6 @@ RSpec.describe RubySMB::SMB2::File do
|
|
408
480
|
expect { file.send_recv_read }.to raise_error(RubySMB::Error::InvalidPacket)
|
409
481
|
end
|
410
482
|
|
411
|
-
context 'when the response status code is STATUS_PENDING' do
|
412
|
-
before :example do
|
413
|
-
allow(file).to receive(:sleep)
|
414
|
-
allow(read_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_PENDING)
|
415
|
-
allow(dispatcher).to receive(:recv_packet).and_return(raw_response)
|
416
|
-
end
|
417
|
-
|
418
|
-
it 'wait 1 second and calls Client dispatcher #recv_packet method one more time' do
|
419
|
-
expect(file).to receive(:sleep).with(1)
|
420
|
-
expect(dispatcher).to receive(:recv_packet)
|
421
|
-
file.send_recv_read
|
422
|
-
end
|
423
|
-
|
424
|
-
it 'parses the response as a SMB2 ReadResponse packet' do
|
425
|
-
expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).twice.with(raw_response)
|
426
|
-
file.send_recv_read
|
427
|
-
end
|
428
|
-
|
429
|
-
it 'raises an InvalidPacket exception if the response is not valid' do
|
430
|
-
allow(dispatcher).to receive(:recv_packet) do
|
431
|
-
allow(read_response).to receive(:valid?).and_return(false)
|
432
|
-
raw_response
|
433
|
-
end
|
434
|
-
expect { file.send_recv_read }.to raise_error(RubySMB::Error::InvalidPacket)
|
435
|
-
end
|
436
|
-
end
|
437
|
-
|
438
483
|
it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS' do
|
439
484
|
allow(read_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
|
440
485
|
expect { file.send_recv_read }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
@@ -457,7 +502,7 @@ RSpec.describe RubySMB::SMB2::File do
|
|
457
502
|
|
458
503
|
before :example do
|
459
504
|
allow(file).to receive(:write_packet).and_return(request)
|
460
|
-
allow(client).to receive(:send_recv).and_return(raw_response)
|
505
|
+
allow(client).to receive(:send_recv).and_return(raw_response, encrypt: false)
|
461
506
|
allow(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).with(raw_response).and_return(write_response)
|
462
507
|
end
|
463
508
|
|
@@ -478,40 +523,19 @@ RSpec.describe RubySMB::SMB2::File do
|
|
478
523
|
end
|
479
524
|
|
480
525
|
it 'calls Client #send_recv with the expected request' do
|
481
|
-
expect(client).to receive(:send_recv).with(request)
|
526
|
+
expect(client).to receive(:send_recv).with(request, encrypt: false)
|
482
527
|
file.send_recv_write
|
483
528
|
end
|
484
529
|
|
485
|
-
it '
|
486
|
-
|
530
|
+
it 'calls Client #send_recv with encryption set if required' do
|
531
|
+
file.encryption_required = true
|
532
|
+
expect(client).to receive(:send_recv).with(request, encrypt: true)
|
487
533
|
file.send_recv_write
|
488
534
|
end
|
489
535
|
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
allow(write_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_PENDING)
|
494
|
-
allow(dispatcher).to receive(:recv_packet).and_return(raw_response)
|
495
|
-
end
|
496
|
-
|
497
|
-
it 'wait 1 second and calls Client dispatcher #recv_packet method one more time' do
|
498
|
-
expect(file).to receive(:sleep).with(1)
|
499
|
-
expect(dispatcher).to receive(:recv_packet)
|
500
|
-
file.send_recv_write
|
501
|
-
end
|
502
|
-
|
503
|
-
it 'parses the response as a SMB2 WriteResponse packet' do
|
504
|
-
expect(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).twice.with(raw_response)
|
505
|
-
file.send_recv_write
|
506
|
-
end
|
507
|
-
|
508
|
-
it 'raises an InvalidPacket exception if the response is not valid' do
|
509
|
-
allow(dispatcher).to receive(:recv_packet) do
|
510
|
-
allow(write_response).to receive(:valid?).and_return(false)
|
511
|
-
raw_response
|
512
|
-
end
|
513
|
-
expect { file.send_recv_write }.to raise_error(RubySMB::Error::InvalidPacket)
|
514
|
-
end
|
536
|
+
it 'parses the response as a SMB1 WriteResponse packet' do
|
537
|
+
expect(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).with(raw_response)
|
538
|
+
file.send_recv_write
|
515
539
|
end
|
516
540
|
|
517
541
|
it 'raises an InvalidPacket exception if the response is not valid' do
|