ruby_smb 1.1.0 → 2.0.0
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 +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
|