backup 3.0.26 → 3.0.27
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.
- data/README.md +1 -3
- data/lib/backup/cli/helpers.rb +2 -0
- data/lib/backup/cli/utility.rb +4 -4
- data/lib/backup/compressor/bzip2.rb +8 -4
- data/lib/backup/compressor/gzip.rb +8 -4
- data/lib/backup/configuration/helpers.rb +30 -38
- data/lib/backup/database/mongodb.rb +2 -1
- data/lib/backup/database/mysql.rb +2 -1
- data/lib/backup/database/postgresql.rb +2 -1
- data/lib/backup/database/redis.rb +2 -1
- data/lib/backup/database/riak.rb +2 -1
- data/lib/backup/encryptor/gpg.rb +717 -37
- data/lib/backup/syncer/cloud/base.rb +2 -2
- data/lib/backup/version.rb +1 -1
- data/spec-live/backups/config.rb +14 -84
- data/spec-live/backups/config.yml.template +3 -0
- data/spec-live/backups/models.rb +184 -0
- data/spec-live/encryptor/gpg_keys.rb +239 -0
- data/spec-live/encryptor/gpg_spec.rb +287 -0
- data/spec-live/notifier/mail_spec.rb +58 -22
- data/spec-live/spec_helper.rb +69 -3
- data/spec/cli/helpers_spec.rb +25 -25
- data/spec/cli/utility_spec.rb +6 -3
- data/spec/compressor/bzip2_spec.rb +20 -41
- data/spec/compressor/gzip_spec.rb +20 -41
- data/spec/configuration/helpers_spec.rb +94 -253
- data/spec/database/mongodb_spec.rb +9 -10
- data/spec/database/mysql_spec.rb +9 -10
- data/spec/database/postgresql_spec.rb +9 -10
- data/spec/database/redis_spec.rb +9 -10
- data/spec/database/riak_spec.rb +9 -10
- data/spec/encryptor/gpg_spec.rb +830 -71
- data/spec/storage/dropbox_spec.rb +24 -36
- data/spec/syncer/cloud/base_spec.rb +1 -1
- data/templates/cli/utility/encryptor/gpg +16 -1
- metadata +63 -64
data/spec/database/mysql_spec.rb
CHANGED
@@ -374,19 +374,18 @@ describe Backup::Database::MySQL do
|
|
374
374
|
end
|
375
375
|
|
376
376
|
describe 'deprecations' do
|
377
|
-
after do
|
378
|
-
Backup::Database::MySQL.clear_defaults!
|
379
|
-
end
|
380
|
-
|
381
377
|
describe '#utility_path' do
|
382
378
|
before do
|
383
379
|
Backup::Database::MySQL.any_instance.stubs(:utility)
|
384
|
-
Backup::Logger.expects(:warn).with
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
380
|
+
Backup::Logger.expects(:warn).with {|err|
|
381
|
+
err.should be_an_instance_of Backup::Errors::ConfigurationError
|
382
|
+
err.message.should match(
|
383
|
+
/Use MySQL#mysqldump_utility instead/
|
384
|
+
)
|
385
|
+
}
|
386
|
+
end
|
387
|
+
after do
|
388
|
+
Backup::Database::MySQL.clear_defaults!
|
390
389
|
end
|
391
390
|
|
392
391
|
context 'when set directly' do
|
@@ -316,19 +316,18 @@ describe Backup::Database::PostgreSQL do
|
|
316
316
|
end
|
317
317
|
|
318
318
|
describe 'deprecations' do
|
319
|
-
after do
|
320
|
-
Backup::Database::PostgreSQL.clear_defaults!
|
321
|
-
end
|
322
|
-
|
323
319
|
describe '#utility_path' do
|
324
320
|
before do
|
325
321
|
Backup::Database::PostgreSQL.any_instance.stubs(:utility)
|
326
|
-
Backup::Logger.expects(:warn).with
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
322
|
+
Backup::Logger.expects(:warn).with {|err|
|
323
|
+
err.should be_an_instance_of Backup::Errors::ConfigurationError
|
324
|
+
err.message.should match(
|
325
|
+
/Use PostgreSQL#pg_dump_utility instead/
|
326
|
+
)
|
327
|
+
}
|
328
|
+
end
|
329
|
+
after do
|
330
|
+
Backup::Database::PostgreSQL.clear_defaults!
|
332
331
|
end
|
333
332
|
|
334
333
|
context 'when set directly' do
|
data/spec/database/redis_spec.rb
CHANGED
@@ -297,19 +297,18 @@ describe Backup::Database::Redis do
|
|
297
297
|
end
|
298
298
|
|
299
299
|
describe 'deprecations' do
|
300
|
-
after do
|
301
|
-
Backup::Database::Redis.clear_defaults!
|
302
|
-
end
|
303
|
-
|
304
300
|
describe '#utility_path' do
|
305
301
|
before do
|
306
302
|
Backup::Database::Redis.any_instance.stubs(:utility)
|
307
|
-
Backup::Logger.expects(:warn).with
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
303
|
+
Backup::Logger.expects(:warn).with {|err|
|
304
|
+
err.should be_an_instance_of Backup::Errors::ConfigurationError
|
305
|
+
err.message.should match(
|
306
|
+
/Use Redis#redis_cli_utility instead/
|
307
|
+
)
|
308
|
+
}
|
309
|
+
end
|
310
|
+
after do
|
311
|
+
Backup::Database::Redis.clear_defaults!
|
313
312
|
end
|
314
313
|
|
315
314
|
context 'when set directly' do
|
data/spec/database/riak_spec.rb
CHANGED
@@ -139,19 +139,18 @@ describe Backup::Database::Riak do
|
|
139
139
|
end
|
140
140
|
|
141
141
|
describe 'deprecations' do
|
142
|
-
after do
|
143
|
-
Backup::Database::Riak.clear_defaults!
|
144
|
-
end
|
145
|
-
|
146
142
|
describe '#utility_path' do
|
147
143
|
before do
|
148
144
|
Backup::Database::Riak.any_instance.stubs(:utility)
|
149
|
-
Backup::Logger.expects(:warn).with
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
145
|
+
Backup::Logger.expects(:warn).with {|err|
|
146
|
+
err.should be_an_instance_of Backup::Errors::ConfigurationError
|
147
|
+
err.message.should match(
|
148
|
+
/Use Riak#riak_admin_utility instead/
|
149
|
+
)
|
150
|
+
}
|
151
|
+
end
|
152
|
+
after do
|
153
|
+
Backup::Database::Riak.clear_defaults!
|
155
154
|
end
|
156
155
|
|
157
156
|
context 'when set directly' do
|
data/spec/encryptor/gpg_spec.rb
CHANGED
@@ -5,7 +5,8 @@ require File.expand_path('../../spec_helper.rb', __FILE__)
|
|
5
5
|
describe Backup::Encryptor::GPG do
|
6
6
|
let(:encryptor) do
|
7
7
|
Backup::Encryptor::GPG.new do |e|
|
8
|
-
e.
|
8
|
+
e.mode = :symmetric
|
9
|
+
e.passphrase = 'test secret'
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
@@ -14,6 +15,30 @@ describe Backup::Encryptor::GPG do
|
|
14
15
|
superclass.should == Backup::Encryptor::Base
|
15
16
|
end
|
16
17
|
|
18
|
+
it 'supports three modes of operation' do
|
19
|
+
Backup::Encryptor::GPG::MODES.should == [:asymmetric, :symmetric, :both]
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#mode=' do
|
23
|
+
it 'should accept valid modes' do
|
24
|
+
mode = Backup::Encryptor::GPG::MODES.shuffle.first
|
25
|
+
encryptor.mode = mode
|
26
|
+
encryptor.mode.should == mode
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should convert string input to a symbol' do
|
30
|
+
mode = Backup::Encryptor::GPG::MODES.shuffle.first
|
31
|
+
encryptor.mode = mode.to_s
|
32
|
+
encryptor.mode.should == mode
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should raise an error for invalid modes' do
|
36
|
+
expect do
|
37
|
+
encryptor.mode = 'foo'
|
38
|
+
end.to raise_error(Backup::Errors::Encryptor::GPG::InvalidModeError)
|
39
|
+
end
|
40
|
+
end # describe '#mode='
|
41
|
+
|
17
42
|
describe '#initialize' do
|
18
43
|
after { Backup::Encryptor::GPG.clear_defaults! }
|
19
44
|
|
@@ -24,127 +49,861 @@ describe Backup::Encryptor::GPG do
|
|
24
49
|
|
25
50
|
context 'when no pre-configured defaults have been set' do
|
26
51
|
it 'should use the values given' do
|
27
|
-
encryptor.
|
52
|
+
encryptor.mode.should == :symmetric
|
53
|
+
encryptor.passphrase.should == 'test secret'
|
28
54
|
end
|
29
55
|
|
30
56
|
it 'should use default values if none are given' do
|
31
57
|
encryptor = Backup::Encryptor::GPG.new
|
32
|
-
encryptor.
|
58
|
+
encryptor.mode.should == :asymmetric
|
59
|
+
encryptor.keys.should be_nil
|
60
|
+
encryptor.recipients.should be_nil
|
61
|
+
encryptor.passphrase.should be_nil
|
62
|
+
encryptor.passphrase_file.should be_nil
|
63
|
+
encryptor.gpg_config.should be_nil
|
64
|
+
encryptor.gpg_homedir.should be_nil
|
33
65
|
end
|
34
66
|
end # context 'when no pre-configured defaults have been set'
|
35
67
|
|
36
68
|
context 'when pre-configured defaults have been set' do
|
37
69
|
before do
|
38
70
|
Backup::Encryptor::GPG.defaults do |e|
|
39
|
-
e.
|
71
|
+
e.mode = :both
|
72
|
+
e.keys = { 'test_key' => 'test public key' }
|
73
|
+
e.recipients = 'test_key'
|
74
|
+
e.passphrase_file = 'my/pass/file'
|
40
75
|
end
|
41
76
|
end
|
42
77
|
|
43
78
|
it 'should use pre-configured defaults' do
|
44
79
|
encryptor = Backup::Encryptor::GPG.new
|
45
|
-
encryptor.
|
80
|
+
encryptor.mode.should == :both
|
81
|
+
encryptor.keys.should == { 'test_key' => 'test public key' }
|
82
|
+
encryptor.recipients.should == 'test_key'
|
83
|
+
encryptor.passphrase_file.should == 'my/pass/file'
|
46
84
|
end
|
47
85
|
|
48
86
|
it 'should override pre-configured defaults' do
|
49
|
-
encryptor.
|
87
|
+
encryptor.mode.should == :symmetric
|
88
|
+
encryptor.keys.should == { 'test_key' => 'test public key' }
|
89
|
+
encryptor.recipients.should == 'test_key'
|
90
|
+
encryptor.passphrase.should == 'test secret'
|
91
|
+
encryptor.passphrase_file.should == 'my/pass/file'
|
50
92
|
end
|
51
93
|
end # context 'when pre-configured defaults have been set'
|
52
94
|
end # describe '#initialize'
|
53
95
|
|
54
96
|
describe '#encrypt_with' do
|
55
|
-
|
97
|
+
before do
|
56
98
|
encryptor.expects(:log!)
|
57
|
-
encryptor.expects(:
|
58
|
-
encryptor.expects(:
|
59
|
-
|
99
|
+
encryptor.expects(:prepare)
|
100
|
+
encryptor.expects(:cleanup) # ensure call
|
101
|
+
end
|
60
102
|
|
61
|
-
|
62
|
-
|
63
|
-
|
103
|
+
context 'when encryption can be performed' do
|
104
|
+
it 'should yield the encryption command and extension' do
|
105
|
+
encryptor.expects(:mode_options).twice.returns('mode_options')
|
106
|
+
encryptor.expects(:base_options).returns('base_options')
|
107
|
+
encryptor.expects(:utility).with(:gpg).returns('gpg')
|
108
|
+
|
109
|
+
encryptor.encrypt_with do |command, ext|
|
110
|
+
command.should == 'gpg base_options mode_options'
|
111
|
+
ext.should == '.gpg'
|
112
|
+
end
|
64
113
|
end
|
65
114
|
end
|
66
|
-
end
|
67
115
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
116
|
+
context 'when encryption can not be performed' do
|
117
|
+
it 'should raise an error when no mode_options are returned' do
|
118
|
+
encryptor.expects(:mode_options).returns([])
|
119
|
+
|
120
|
+
expect do
|
121
|
+
encryptor.encrypt_with
|
122
|
+
end.to raise_error(Backup::Errors::Encryptor::GPG::EncryptionError)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end # describe '#encrypt_with'
|
74
126
|
|
75
|
-
|
76
|
-
|
127
|
+
describe '#prepare and #cleanup' do
|
128
|
+
it 'should setup required variables' do
|
129
|
+
encryptor.instance_variable_set(:@tempdirs, nil)
|
130
|
+
FileUtils.expects(:rm_rf).never
|
131
|
+
encryptor.send(:prepare)
|
132
|
+
encryptor.instance_variable_get(:@tempdirs).should == []
|
77
133
|
end
|
78
134
|
|
79
|
-
it 'should
|
80
|
-
encryptor.instance_variable_set(:@
|
81
|
-
|
82
|
-
encryptor.expects(:with_tmp_key_file).never
|
83
|
-
encryptor.expects(:run).never
|
135
|
+
it 'should remove any tempdirs and clear all variables' do
|
136
|
+
encryptor.instance_variable_set(:@tempdirs, ['a', 'b'])
|
137
|
+
FileUtils.expects(:rm_rf).with(['a', 'b'], {:secure => true})
|
84
138
|
|
85
|
-
encryptor.
|
139
|
+
encryptor.instance_variable_set(:@base_options, true)
|
140
|
+
encryptor.instance_variable_set(:@mode_options, true)
|
141
|
+
encryptor.instance_variable_set(:@user_recipients, true)
|
142
|
+
encryptor.instance_variable_set(:@user_keys, true)
|
143
|
+
encryptor.instance_variable_set(:@system_identifiers, true)
|
144
|
+
|
145
|
+
encryptor.send(:cleanup)
|
146
|
+
|
147
|
+
encryptor.instance_variable_get(:@tempdirs).should == []
|
148
|
+
encryptor.instance_variable_get(:@base_options).should be_nil
|
149
|
+
encryptor.instance_variable_get(:@mode_options).should be_nil
|
150
|
+
encryptor.instance_variable_get(:@user_recipients).should be_nil
|
151
|
+
encryptor.instance_variable_get(:@user_keys).should be_nil
|
152
|
+
encryptor.instance_variable_get(:@system_identifiers).should be_nil
|
86
153
|
end
|
87
|
-
end
|
154
|
+
end # describe '#prepare and #cleanup'
|
155
|
+
|
156
|
+
describe '#base_options' do
|
157
|
+
context 'while caching the return value in @base_options' do
|
158
|
+
before { encryptor.instance_variable_set(:@base_options, nil) }
|
159
|
+
|
160
|
+
context 'when #gpg_homedir is given' do
|
161
|
+
it 'should return the proper options' do
|
162
|
+
encryptor.expects(:setup_gpg_homedir).once.returns('/a/dir')
|
163
|
+
encryptor.expects(:setup_gpg_config).once.returns(false)
|
164
|
+
|
165
|
+
ret = "--no-tty --homedir '/a/dir'"
|
166
|
+
encryptor.send(:base_options).should == ret
|
167
|
+
encryptor.send(:base_options).should == ret
|
168
|
+
encryptor.instance_variable_get(:@base_options).should == ret
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context 'when #gpg_config is given' do
|
173
|
+
it 'should return the proper options' do
|
174
|
+
encryptor.expects(:setup_gpg_homedir).once.returns(false)
|
175
|
+
encryptor.expects(:setup_gpg_config).once.returns('/a/file')
|
88
176
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
177
|
+
ret = "--no-tty --options '/a/file'"
|
178
|
+
encryptor.send(:base_options).should == ret
|
179
|
+
encryptor.send(:base_options).should == ret
|
180
|
+
encryptor.instance_variable_get(:@base_options).should == ret
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context 'when #gpg_homedir and #gpg_config is given' do
|
185
|
+
it 'should return the proper options' do
|
186
|
+
encryptor.expects(:setup_gpg_homedir).once.returns('/a/dir')
|
187
|
+
encryptor.expects(:setup_gpg_config).once.returns('/a/file')
|
188
|
+
|
189
|
+
ret = "--no-tty --homedir '/a/dir' --options '/a/file'"
|
190
|
+
encryptor.send(:base_options).should == ret
|
191
|
+
encryptor.send(:base_options).should == ret
|
192
|
+
encryptor.instance_variable_get(:@base_options).should == ret
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'when neither #gpg_homedir and #gpg_config is given' do
|
197
|
+
it 'should return the proper options' do
|
198
|
+
encryptor.expects(:setup_gpg_homedir).once.returns(false)
|
199
|
+
encryptor.expects(:setup_gpg_config).once.returns(false)
|
200
|
+
|
201
|
+
ret = '--no-tty'
|
202
|
+
encryptor.send(:base_options).should == ret
|
203
|
+
encryptor.send(:base_options).should == ret
|
204
|
+
encryptor.instance_variable_get(:@base_options).should == ret
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end # describe '#base_options'
|
209
|
+
|
210
|
+
describe '#setup_gpg_homedir' do
|
211
|
+
context 'when #gpg_homedir is not set' do
|
212
|
+
it 'should return false' do
|
213
|
+
encryptor.gpg_homedir = nil
|
214
|
+
encryptor.send(:setup_gpg_homedir).should be_false
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
context 'when #gpg_homedir is set' do
|
219
|
+
let(:path) { 'some/path' }
|
220
|
+
let(:expanded_path) { File.expand_path(path) }
|
221
|
+
|
222
|
+
before do
|
223
|
+
encryptor.gpg_homedir = path
|
224
|
+
Backup::Config.stubs(:user).returns('a_user')
|
225
|
+
end
|
226
|
+
|
227
|
+
context 'and no errors occur' do
|
228
|
+
before do
|
229
|
+
FileUtils.expects(:mkdir_p).with(expanded_path)
|
230
|
+
FileUtils.expects(:chown).with('a_user', nil, expanded_path)
|
231
|
+
FileUtils.expects(:chmod).with(0700, expanded_path)
|
232
|
+
end
|
233
|
+
|
234
|
+
context 'and the gpg_homedir files exist' do
|
235
|
+
before do
|
236
|
+
%w{ pubring.gpg secring.gpg trustdb.gpg }.each do |file|
|
237
|
+
File.expects(:exist?).with(
|
238
|
+
File.join(expanded_path, file)
|
239
|
+
).returns(true)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'should ensure permissions and return the path' do
|
244
|
+
encryptor.expects(:utility).never
|
245
|
+
encryptor.send(:setup_gpg_homedir).should == expanded_path
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
context 'and the gpg_homedir files do not exist' do
|
250
|
+
before do
|
251
|
+
File.stubs(:exist?).returns(false)
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'should call gpg to initialize the files' do
|
255
|
+
encryptor.expects(:utility).with(:gpg).returns('gpg')
|
256
|
+
encryptor.expects(:run).with(
|
257
|
+
"gpg --homedir '#{ expanded_path }' -K 2>&1 >/dev/null"
|
258
|
+
)
|
259
|
+
encryptor.send(:setup_gpg_homedir).should == expanded_path
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'and errors occur' do
|
265
|
+
it 'should wrap and raise the error' do
|
266
|
+
File.expects(:expand_path).raises('error message')
|
267
|
+
|
268
|
+
expect do
|
269
|
+
encryptor.send(:setup_gpg_homedir)
|
270
|
+
end.to raise_error {|err|
|
271
|
+
err.should
|
272
|
+
be_an_instance_of Backup::Errors::Encryptor::GPG::HomedirError
|
273
|
+
err.message.should
|
274
|
+
match(/Reason: RuntimeError\n error message/)
|
275
|
+
}
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end # describe '#setup_gpg_homedir'
|
280
|
+
|
281
|
+
describe '#setup_gpg_config' do
|
282
|
+
context 'when #gpg_config is not set' do
|
283
|
+
it 'should return false' do
|
284
|
+
encryptor.gpg_config = nil
|
285
|
+
encryptor.send(:setup_gpg_config).should be_false
|
286
|
+
end
|
93
287
|
end
|
94
|
-
end
|
95
288
|
|
96
|
-
|
97
|
-
|
98
|
-
|
289
|
+
context 'when #gpg_config is set' do
|
290
|
+
before do
|
291
|
+
encryptor.gpg_config = <<-EOF
|
292
|
+
# a comment
|
293
|
+
text which will be
|
294
|
+
|
295
|
+
\tthe content of a gpg.conf file
|
296
|
+
EOF
|
297
|
+
Backup::Config.stubs(:tmp_path).returns('/Backup/tmp')
|
298
|
+
encryptor.instance_variable_set(:@tempdirs, [])
|
299
|
+
end
|
300
|
+
|
301
|
+
context 'when no errors occur' do
|
302
|
+
let(:tempdir) { mock }
|
303
|
+
let(:tempfile) { mock }
|
304
|
+
let(:tempfile_path) { mock }
|
305
|
+
let(:path) { mock }
|
306
|
+
|
307
|
+
before do
|
308
|
+
encryptor.expects(:cleanup).never
|
309
|
+
tempfile.stubs(:path).returns(tempfile_path)
|
310
|
+
end
|
311
|
+
|
312
|
+
it 'should create and return the file path' do
|
313
|
+
# create temporary directory and convert to a Pathname object
|
314
|
+
Dir.expects(:mktmpdir).with(
|
315
|
+
'backup-gpg_config', '/Backup/tmp'
|
316
|
+
).returns(tempdir)
|
317
|
+
|
318
|
+
# create temporary file within the temporary directory
|
319
|
+
Tempfile.expects(:open).with(
|
320
|
+
'backup-gpg_config', tempdir
|
321
|
+
).returns(tempfile)
|
322
|
+
|
323
|
+
# write the gpg_config, stripping leading tabs/spaces
|
324
|
+
tempfile.expects(:write).with(
|
325
|
+
"# a comment\n" +
|
326
|
+
"text which will be\n" +
|
327
|
+
"\n" +
|
328
|
+
"the content of a gpg.conf file\n"
|
329
|
+
)
|
330
|
+
# close the file
|
331
|
+
tempfile.expects(:close)
|
332
|
+
|
333
|
+
# check the config file
|
334
|
+
encryptor.expects(:check_gpg_config).with(tempfile_path)
|
335
|
+
|
336
|
+
# method returns the tempfile's path
|
337
|
+
encryptor.send(:setup_gpg_config).should == tempfile_path
|
338
|
+
|
339
|
+
# tempdir added to @tempdirs
|
340
|
+
encryptor.instance_variable_get(:@tempdirs)[0].should == tempdir
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
context 'when errors occur' do
|
345
|
+
before do
|
346
|
+
encryptor.expects(:cleanup) # run before the error is raised
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'should wrap and raise the error' do
|
350
|
+
Dir.expects(:mktmpdir).raises('an error')
|
351
|
+
|
352
|
+
expect do
|
353
|
+
encryptor.send(:setup_gpg_config)
|
354
|
+
end.to raise_error {|err|
|
355
|
+
err.should be_an_instance_of(
|
356
|
+
Backup::Errors::Encryptor::GPG::GPGConfigError
|
357
|
+
)
|
358
|
+
err.message.should match(
|
359
|
+
/Error creating temporary file for #gpg_config/
|
360
|
+
)
|
361
|
+
err.message.should match(
|
362
|
+
/Reason: RuntimeError\n an error/
|
363
|
+
)
|
364
|
+
}
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end # describe '#setup_gpg_config'
|
369
|
+
|
370
|
+
describe '#check_gpg_config' do
|
371
|
+
let(:cmd_ret) { mock }
|
372
|
+
let(:file_path) { '/path/to/tempfile' }
|
99
373
|
|
100
374
|
before do
|
101
|
-
|
102
|
-
encryptor.
|
375
|
+
encryptor.expects(:utility).with(:gpg).returns('gpg')
|
376
|
+
encryptor.expects(:run).with(
|
377
|
+
"gpg --options '#{ file_path }' --gpgconf-test 2>&1"
|
378
|
+
).returns(cmd_ret)
|
103
379
|
end
|
104
380
|
|
105
|
-
|
106
|
-
|
107
|
-
with('backup.pub').
|
108
|
-
returns(tmp_file)
|
109
|
-
FileUtils.expects(:chown).in_sequence(s).
|
110
|
-
with(Backup::Config.user, nil, '/path/to/tmp_file')
|
111
|
-
FileUtils.expects(:chmod).in_sequence(s).
|
112
|
-
with(0600, '/path/to/tmp_file')
|
113
|
-
tmp_file.expects(:write).in_sequence(s).
|
114
|
-
with('provided key')
|
115
|
-
tmp_file.expects(:close).in_sequence(s)
|
116
|
-
tmp_file.expects(:delete).in_sequence(s)
|
381
|
+
context 'when no errors are reported' do
|
382
|
+
before { cmd_ret.expects(:chomp).returns('') }
|
117
383
|
|
118
|
-
|
119
|
-
|
384
|
+
it 'should do nothing' do
|
385
|
+
encryptor.send(:check_gpg_config, file_path).should be_nil
|
120
386
|
end
|
121
387
|
end
|
122
|
-
end
|
123
388
|
|
124
|
-
|
125
|
-
|
126
|
-
|
389
|
+
context 'when errors are reported' do
|
390
|
+
let(:error_message) { "gpg: /path/to/tempfile:1: invalid option" }
|
391
|
+
before { cmd_ret.expects(:chomp).returns(error_message) }
|
392
|
+
|
393
|
+
it 'should raise the error message reported' do
|
394
|
+
expect do
|
395
|
+
encryptor.send(:check_gpg_config, file_path)
|
396
|
+
end.to raise_error(RuntimeError, error_message)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end # describe '#check_gpg_config'
|
400
|
+
|
401
|
+
describe '#mode_options' do
|
402
|
+
let(:s_opts) { "-c --passphrase_file '/some/file'" }
|
403
|
+
let(:a_opts) { "-e --trust-model always -r 'identifier'" }
|
404
|
+
|
405
|
+
context 'while caching the return value in @mode_options' do
|
406
|
+
before { encryptor.instance_variable_set(:@mode_options, nil) }
|
407
|
+
|
408
|
+
context 'when #mode is :symmetric' do
|
409
|
+
it 'should return symmetric encryption options' do
|
410
|
+
encryptor.expects(:symmetric_options).once.returns(s_opts)
|
411
|
+
encryptor.expects(:asymmetric_options).never
|
412
|
+
|
413
|
+
encryptor.mode = :symmetric
|
414
|
+
encryptor.send(:mode_options).should == s_opts
|
415
|
+
encryptor.send(:mode_options).should == s_opts
|
416
|
+
encryptor.instance_variable_get(:@mode_options).should == s_opts
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
context 'when #mode is :asymmetric' do
|
421
|
+
it 'should return asymmetric encryption options' do
|
422
|
+
encryptor.expects(:symmetric_options).never
|
423
|
+
encryptor.expects(:asymmetric_options).once.returns(a_opts)
|
424
|
+
|
425
|
+
encryptor.mode = :asymmetric
|
426
|
+
encryptor.send(:mode_options).should == a_opts
|
427
|
+
encryptor.send(:mode_options).should == a_opts
|
428
|
+
encryptor.instance_variable_get(:@mode_options).should == a_opts
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
context 'when #mode is :both' do
|
433
|
+
it 'should return both symmetric and asymmetric encryption options' do
|
434
|
+
encryptor.expects(:symmetric_options).once.returns(s_opts)
|
435
|
+
encryptor.expects(:asymmetric_options).once.returns(a_opts)
|
436
|
+
|
437
|
+
encryptor.mode = :both
|
438
|
+
opts = "#{ s_opts } #{ a_opts }"
|
439
|
+
|
440
|
+
encryptor.send(:mode_options).should == opts
|
441
|
+
encryptor.send(:mode_options).should == opts
|
442
|
+
encryptor.instance_variable_get(:@mode_options).should == opts
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end # describe '#mode_options'
|
447
|
+
|
448
|
+
describe '#symmetric_options' do
|
449
|
+
let(:path) { '/path/to/passphrase/file' }
|
450
|
+
let(:s_opts) { "-c --passphrase-file '#{ path }'" }
|
451
|
+
|
452
|
+
context 'when setup_passphrase_file returns a path' do
|
453
|
+
it 'should return the options' do
|
454
|
+
encryptor.expects(:setup_passphrase_file).returns(path)
|
455
|
+
File.expects(:exist?).with(path).returns(true)
|
456
|
+
|
457
|
+
encryptor.send(:symmetric_options).should == s_opts
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
context 'when setup_passphrase_file returns false' do
|
462
|
+
before do
|
463
|
+
encryptor.expects(:setup_passphrase_file).returns(false)
|
464
|
+
end
|
465
|
+
|
466
|
+
context 'and no :passphrase_file is set' do
|
467
|
+
it 'should return nil and log a warning' do
|
468
|
+
encryptor.expects(:passphrase_file).returns(nil)
|
469
|
+
Backup::Logger.expects(:warn)
|
470
|
+
|
471
|
+
encryptor.send(:symmetric_options).should be_nil
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
context 'and a :passphrase_file is set' do
|
476
|
+
before do
|
477
|
+
encryptor.expects(:passphrase_file).twice.returns(path)
|
478
|
+
File.expects(:expand_path).with(path).returns(path)
|
479
|
+
end
|
480
|
+
|
481
|
+
context 'when :passphrase_file exists' do
|
482
|
+
it 'should return the options' do
|
483
|
+
File.expects(:exist?).with(path).returns(true)
|
484
|
+
encryptor.send(:symmetric_options).should == s_opts
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
context 'when :passphrase_file is no valid' do
|
489
|
+
it 'should return nil and log a warning' do
|
490
|
+
File.expects(:exist?).with(path).returns(false)
|
491
|
+
Backup::Logger.expects(:warn)
|
492
|
+
encryptor.send(:symmetric_options).should be_nil
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end # describe '#symmetric_options'
|
498
|
+
|
499
|
+
describe '#setup_passphrase_file' do
|
500
|
+
context 'when :passphrase is not set' do
|
501
|
+
it 'should return false' do
|
502
|
+
encryptor.expects(:passphrase).returns(nil)
|
503
|
+
encryptor.send(:setup_passphrase_file).should be_false
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
context 'when :passphrase is set' do
|
508
|
+
let(:tempdir) { mock }
|
509
|
+
let(:tempfile) { mock }
|
510
|
+
let(:tempfile_path) { mock }
|
511
|
+
|
512
|
+
before do
|
513
|
+
encryptor.instance_variable_set(:@tempdirs, [])
|
514
|
+
Backup::Config.stubs(:tmp_path).returns('/Backup/tmp')
|
515
|
+
encryptor.stubs(:passphrase).returns('a secret')
|
516
|
+
tempfile.stubs(:path).returns(tempfile_path)
|
517
|
+
end
|
518
|
+
|
519
|
+
context 'and no errors occur' do
|
520
|
+
it 'should return the path for the temp file' do
|
521
|
+
# creates temporary directory in Config.tmp_path
|
522
|
+
Dir.expects(:mktmpdir).
|
523
|
+
with('backup-gpg_passphrase', '/Backup/tmp').
|
524
|
+
returns(tempdir)
|
525
|
+
|
526
|
+
# create the temporary file in that temporary directory
|
527
|
+
Tempfile.expects(:open).
|
528
|
+
with('backup-gpg_passphrase', tempdir).
|
529
|
+
returns(tempfile)
|
530
|
+
tempfile.expects(:write).with('a secret')
|
531
|
+
tempfile.expects(:close)
|
532
|
+
|
533
|
+
encryptor.send(:setup_passphrase_file).should == tempfile_path
|
534
|
+
|
535
|
+
# adds the temporary directory to @tempdirs
|
536
|
+
encryptor.instance_variable_get(:@tempdirs)[0].should == tempdir
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
context 'and an error occurs' do
|
541
|
+
it 'should return false and log a warning' do
|
542
|
+
Dir.expects(:mktmpdir).raises('an error')
|
543
|
+
Backup::Logger.expects(:warn).with do |err|
|
544
|
+
err.should be_an_instance_of(
|
545
|
+
Backup::Errors::Encryptor::GPG::PassphraseError
|
546
|
+
)
|
547
|
+
err.message.should match(
|
548
|
+
/Reason: RuntimeError\n an error/
|
549
|
+
)
|
550
|
+
end
|
551
|
+
encryptor.send(:setup_passphrase_file).should be_false
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
end
|
556
|
+
end # describe '#setup_passphrase_file'
|
557
|
+
|
558
|
+
describe '#asymmetric_options' do
|
559
|
+
context 'when recipients are found' do
|
560
|
+
it 'should return the options' do
|
561
|
+
encryptor.stubs(:user_recipients).returns(['keyid1', 'keyid2'])
|
562
|
+
encryptor.send(:asymmetric_options).should ==
|
563
|
+
"-e --trust-model always -r 'keyid1' -r 'keyid2'"
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
context 'when no recipients are found' do
|
568
|
+
it 'should return nil log a warning' do
|
569
|
+
encryptor.expects(:user_recipients).returns([])
|
570
|
+
Backup::Logger.expects(:warn)
|
571
|
+
encryptor.send(:asymmetric_options).should be_nil
|
572
|
+
end
|
573
|
+
end
|
574
|
+
end # describe '#asymmetric_options'
|
575
|
+
|
576
|
+
describe '#user_recipients' do
|
577
|
+
context 'when an Array of :recipients are given' do
|
578
|
+
it 'should return the recipient list and cache the result' do
|
579
|
+
encryptor.expects(:recipients).returns(
|
580
|
+
['key_id1', 'key_id2', 'key_id3', 'key_id4']
|
581
|
+
)
|
582
|
+
encryptor.expects(:clean_identifier).with('key_id1').returns('key_id1')
|
583
|
+
encryptor.expects(:clean_identifier).with('key_id2').returns('key_id2')
|
584
|
+
encryptor.expects(:clean_identifier).with('key_id3').returns('key_id3')
|
585
|
+
encryptor.expects(:clean_identifier).with('key_id4').returns('key_id4')
|
586
|
+
|
587
|
+
# key_id1 and key_id3 will be found in the system
|
588
|
+
encryptor.stubs(:system_identifiers).returns(['key_id1', 'key_id3'])
|
589
|
+
|
590
|
+
# key_id2 will be imported (key_id returned)
|
591
|
+
encryptor.stubs(:user_keys).returns({ 'key_id2' => 'a public key' })
|
592
|
+
encryptor.expects(:import_key).
|
593
|
+
with('key_id2', 'a public key').
|
594
|
+
returns('key_id2')
|
595
|
+
|
596
|
+
# key_id4 will not be found in user_keys, so a warning will be logged.
|
597
|
+
# This will return nil into the array, which will be compacted out.
|
598
|
+
Backup::Logger.expects(:warn).with do |msg|
|
599
|
+
msg.should match(/'key_id4'/)
|
600
|
+
end
|
601
|
+
|
602
|
+
encryptor.instance_variable_set(:@user_recipients, nil)
|
603
|
+
recipient_list = ['key_id1', 'key_id2', 'key_id3']
|
604
|
+
encryptor.send(:user_recipients).should == recipient_list
|
605
|
+
# results are cached (expectations would fail if called twice)
|
606
|
+
encryptor.send(:user_recipients).should == recipient_list
|
607
|
+
encryptor.instance_variable_get(:@user_recipients).should == recipient_list
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
context 'when :recipients is a single recipient, given as a String' do
|
612
|
+
it 'should return the cleaned identifier in an Array' do
|
613
|
+
encryptor.expects(:recipients).returns('key_id')
|
614
|
+
# the key will be found in system_identifiers
|
615
|
+
encryptor.stubs(:system_identifiers).returns(['key_id'])
|
616
|
+
encryptor.expects(:clean_identifier).with('key_id').returns('key_id')
|
617
|
+
|
618
|
+
encryptor.send(:user_recipients).should == ['key_id']
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
context 'when :recipients is not set' do
|
623
|
+
it 'should return an empty Array' do
|
624
|
+
encryptor.expects(:recipients).returns(nil)
|
625
|
+
encryptor.send(:user_recipients).should == []
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end # describe '#user_recipients'
|
629
|
+
|
630
|
+
describe '#user_keys' do
|
631
|
+
context 'when :keys has been set' do
|
632
|
+
before do
|
633
|
+
encryptor.expects(:keys).returns(
|
634
|
+
{ 'key1' => :foo, 'key2' => :foo, 'key3' => :foo }
|
635
|
+
)
|
636
|
+
encryptor.instance_variable_set(:@user_keys, nil)
|
637
|
+
end
|
638
|
+
|
639
|
+
it 'should return a new Hash of #keys with cleaned identifiers' do
|
640
|
+
encryptor.expects(:clean_identifier).with('key1').returns('clean_key1')
|
641
|
+
encryptor.expects(:clean_identifier).with('key2').returns('clean_key2')
|
642
|
+
encryptor.expects(:clean_identifier).with('key3').returns('clean_key3')
|
643
|
+
|
644
|
+
Backup::Logger.expects(:warn).never
|
645
|
+
|
646
|
+
cleaned_hash = {
|
647
|
+
'clean_key1' => :foo, 'clean_key2' => :foo, 'clean_key3' => :foo
|
648
|
+
}
|
649
|
+
encryptor.send(:user_keys).should == cleaned_hash
|
650
|
+
# results are cached (expectations would fail if called twice)
|
651
|
+
encryptor.send(:user_keys).should == cleaned_hash
|
652
|
+
encryptor.instance_variable_get(:@user_keys).should == cleaned_hash
|
653
|
+
end
|
654
|
+
|
655
|
+
it 'should log a warning if cleaning results in a duplicate identifier' do
|
656
|
+
encryptor.expects(:clean_identifier).with('key1').returns('clean_key1')
|
657
|
+
encryptor.expects(:clean_identifier).with('key2').returns('clean_key2')
|
658
|
+
# return a duplicate key
|
659
|
+
encryptor.expects(:clean_identifier).with('key3').returns('clean_key2')
|
660
|
+
|
661
|
+
Backup::Logger.expects(:warn)
|
662
|
+
|
663
|
+
cleaned_hash = {
|
664
|
+
'clean_key1' => :foo, 'clean_key2' => :foo
|
665
|
+
}
|
666
|
+
encryptor.send(:user_keys).should == cleaned_hash
|
667
|
+
# results are cached (expectations would fail if called twice)
|
668
|
+
encryptor.send(:user_keys).should == cleaned_hash
|
669
|
+
encryptor.instance_variable_get(:@user_keys).should == cleaned_hash
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
context 'when :keys has not be set' do
|
674
|
+
before do
|
675
|
+
encryptor.expects(:keys).returns(nil)
|
676
|
+
encryptor.instance_variable_set(:@user_keys, nil)
|
677
|
+
end
|
678
|
+
|
679
|
+
it 'should return an empty hash' do
|
680
|
+
encryptor.send(:user_keys).should == {}
|
681
|
+
end
|
682
|
+
end
|
683
|
+
end # describe '#user_keys'
|
684
|
+
|
685
|
+
describe '#clean_identifier' do
|
686
|
+
it 'should remove all spaces and upcase non-email identifiers' do
|
687
|
+
encryptor.send(:clean_identifier, ' 9d66 6290 c5f7 ee0f ').
|
688
|
+
should == '9D666290C5F7EE0F'
|
689
|
+
end
|
690
|
+
|
691
|
+
# Even though spaces in an email are technically possible,
|
692
|
+
# GPG won't allow anything but /[A-Za-z0-9_\-.]/
|
693
|
+
it 'should remove all spaces and wrap email addresses in <>' do
|
694
|
+
emails = [
|
695
|
+
"\t Foo.Bar@example.com ",
|
696
|
+
" < Foo-Bar@example.com\t > ",
|
697
|
+
"< <Foo_Bar @\texample.com> >"
|
698
|
+
]
|
699
|
+
cleaned = [
|
700
|
+
'<Foo.Bar@example.com>',
|
701
|
+
'<Foo-Bar@example.com>',
|
702
|
+
'<Foo_Bar@example.com>'
|
703
|
+
]
|
704
|
+
|
705
|
+
emails.map {|email|
|
706
|
+
encryptor.send(:clean_identifier, email)
|
707
|
+
}.should == cleaned
|
708
|
+
end
|
709
|
+
end # describe '#clean_identifier'
|
710
|
+
|
711
|
+
describe '#import_key' do
|
712
|
+
let(:gpg_return_ok) {
|
713
|
+
<<-EOS.gsub(/^ +/, '')
|
714
|
+
gpg: keyring `/tmp/.gnupg/secring.gpg' created
|
715
|
+
gpg: keyring `/tmp/.gnupg/pubring.gpg' created
|
716
|
+
gpg: /tmp/.gnupg/trustdb.gpg: trustdb created
|
717
|
+
gpg: key 0x9D666290C5F7EE0F: public key "Backup Test <backup01@foo.com>" imported
|
718
|
+
gpg: Total number processed: 1
|
719
|
+
gpg: imported: 1 (RSA: 1)
|
720
|
+
EOS
|
721
|
+
}
|
722
|
+
let(:gpg_return_failed) {
|
723
|
+
<<-EOS.gsub(/^ +/, '')
|
724
|
+
gpg: no valid OpenPGP data found.
|
725
|
+
gpg: Total number processed: 0
|
726
|
+
EOS
|
727
|
+
}
|
728
|
+
let(:gpg_key) {
|
729
|
+
<<-EOS
|
127
730
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
128
|
-
|
731
|
+
Version: GnuPG v1.4.12 (GNU/Linux)
|
129
732
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
=
|
733
|
+
mI0EUAmiNwEEAKpNP4GVKcjJrTtAh0XKk0NQsId6h/1pzEok2bExkNvD6eSjYRFL
|
734
|
+
gXY+pNqaEE6cHrg+uQatVQITX8EoVJhQ9Z1mYJB+g62zqOQPe10Spb381O9y4dN/
|
735
|
+
/ge/yL+/+R2CUrKeNF9nSA24+V4mTSqgo7sTnevDzGj4Srzs76MmkpU=
|
736
|
+
=TU/B
|
134
737
|
-----END PGP PUBLIC KEY BLOCK-----
|
135
|
-
|
738
|
+
EOS
|
739
|
+
}
|
740
|
+
let(:tempfile) { mock }
|
136
741
|
|
137
|
-
|
742
|
+
before do
|
743
|
+
Backup::Config.stubs(:tmp_path).returns('/tmp/path')
|
744
|
+
encryptor.stubs(:base_options).returns("--some 'base options'")
|
745
|
+
encryptor.stubs(:utility).returns('gpg')
|
746
|
+
tempfile.stubs(:path).returns('/tmp/file/path')
|
747
|
+
end
|
748
|
+
|
749
|
+
context 'when the import is successful' do
|
750
|
+
it 'should return the long key ID' do
|
751
|
+
Tempfile.expects(:open).with(
|
752
|
+
'backup-gpg_import', '/tmp/path'
|
753
|
+
).returns(tempfile)
|
754
|
+
tempfile.expects(:write).with(<<-EOS)
|
138
755
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
139
|
-
Version: GnuPG v1.4.
|
756
|
+
Version: GnuPG v1.4.12 (GNU/Linux)
|
140
757
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
=
|
758
|
+
mI0EUAmiNwEEAKpNP4GVKcjJrTtAh0XKk0NQsId6h/1pzEok2bExkNvD6eSjYRFL
|
759
|
+
gXY+pNqaEE6cHrg+uQatVQITX8EoVJhQ9Z1mYJB+g62zqOQPe10Spb381O9y4dN/
|
760
|
+
/ge/yL+/+R2CUrKeNF9nSA24+V4mTSqgo7sTnevDzGj4Srzs76MmkpU=
|
761
|
+
=TU/B
|
145
762
|
-----END PGP PUBLIC KEY BLOCK-----
|
146
|
-
|
763
|
+
EOS
|
764
|
+
|
765
|
+
tempfile.expects(:close)
|
766
|
+
|
767
|
+
encryptor.expects(:run).with(
|
768
|
+
"gpg --some 'base options' --keyid-format 0xlong " +
|
769
|
+
"--import '/tmp/file/path' 2>&1"
|
770
|
+
).returns(gpg_return_ok)
|
771
|
+
|
772
|
+
tempfile.expects(:delete)
|
773
|
+
|
774
|
+
Backup::Logger.expects(:warn).never
|
775
|
+
|
776
|
+
encryptor.send(:import_key, 'some_identifier', gpg_key).
|
777
|
+
should == '9D666290C5F7EE0F'
|
778
|
+
end
|
147
779
|
end
|
148
|
-
end
|
149
780
|
|
781
|
+
context 'when the import is unsuccessful' do
|
782
|
+
it 'should return nil and log a warning' do
|
783
|
+
Tempfile.expects(:open).raises('an error')
|
784
|
+
Backup::Logger.expects(:warn).with {|err|
|
785
|
+
err.should be_an_instance_of(
|
786
|
+
Backup::Errors::Encryptor::GPG::KeyImportError
|
787
|
+
)
|
788
|
+
err.message.should match(
|
789
|
+
/Public key import failed for 'some_identifier'/
|
790
|
+
)
|
791
|
+
err.message.should match(
|
792
|
+
/Reason: RuntimeError\n an error/
|
793
|
+
)
|
794
|
+
}
|
795
|
+
|
796
|
+
encryptor.send(:import_key, 'some_identifier', 'foo').should be_nil
|
797
|
+
end
|
798
|
+
end
|
799
|
+
end # describe '#import_key'
|
800
|
+
|
801
|
+
describe '#system_identifiers' do
|
802
|
+
let(:gpg_output) {
|
803
|
+
<<-EOS.gsub(/^ +/, '')
|
804
|
+
tru::1:1343402941:0:3:1:5
|
805
|
+
pub:-:1024:1:5EFD157FFF9CFEA6:1342808803:::-:::scESC:
|
806
|
+
fpr:::::::::72E56E48E362BB402B3344045EFD157FFF9CFEA6:
|
807
|
+
uid:-::::1342808803::3BED8A0A5100FE9028BEB53610247518594B60A8::Backup Test (No Email):
|
808
|
+
sub:-:1024:1:E6CF1DC860A82E07:1342808803::::::e:
|
809
|
+
pub:-:1024:1:570CE9221E3DA3E8:1342808841:::-:::scESC:
|
810
|
+
fpr:::::::::616BBC8409C1AED791F8E6F8570CE9221E3DA3E8:
|
811
|
+
uid:-::::1342808875::ECFF419EFE4BD3C7CBCCD58FACAD283A9E98FECD::Backup Test <backup04@foo.com>:
|
812
|
+
uid:-::::1342808841::DDFD072C193BB45587EBA9D19A7DA1BB0E5E8A22::Backup Test <backup03@foo.com>:
|
813
|
+
sub:-:1024:1:B65C0ADEB804268D:1342808841::::::e:
|
814
|
+
pub:-:1024:1:54F81C93A7641A16:1342809011:::-:::scESC:
|
815
|
+
fpr:::::::::71335B9B960CF3A3071535F454F81C93A7641A16:
|
816
|
+
uid:-::::1342809011::2E5801E9C064C2A165B61EE35D50A5F9B64BF345::Backup Test (other email is <backup06@foo.com>) <backup05@foo.com>:
|
817
|
+
sub:-:1024:1:5B57BC34628252C7:1342809011::::::e:
|
818
|
+
pub:-:1024:1:0A5B6CC9581A88CF:1342809049:::-:::scESC:
|
819
|
+
fpr:::::::::E8C459082544924B8AEA06280A5B6CC9581A88CF:
|
820
|
+
uid:-::::1342809470::4A404F9ED6780E7E0E02A7F7607828E648789058::Backup Test <backup08@foo.com>:
|
821
|
+
uid:-::::::9785ADEBBBCE94CE0FF25774F610F2B11C839E9B::Backup Test <backup07@foo.com>:
|
822
|
+
uid:r::::::4AD074B1857819EFA105DFB6C464600AA451BF18::Backup Test <backup09@foo.com>:
|
823
|
+
sub:e:1024:1:60A420E39B979B06:1342809049:1342895611:::::e:
|
824
|
+
sub:-:1024:1:A05786E7AD5B8352:1342809166::::::e:
|
825
|
+
pub:i:1024:1:4A83569F4E5E8D8A:1342810132:::-:::esca:
|
826
|
+
fpr:::::::::FFEAD1DB201FB214873E73994A83569F4E5E8D8A:
|
827
|
+
uid:-::::::3D41A10AF2437C8C5BF6050FA80FE20CE30769BF::Backup Test <backup10@foo.com>:
|
828
|
+
sub:i:1024:1:662F18DB92C8DFD8:1342810132::::::e:
|
829
|
+
pub:r:1024:1:15ECEF9ECA136FFF:1342810387:::-:::sc:
|
830
|
+
fpr:::::::::3D1CBF3FEFCE5ABB728922F615ECEF9ECA136FFF:
|
831
|
+
uid:r::::1342810387::296434E1662AE0B2FF8E93EC3BF3AFE24514D0E0::Backup Test <backup11@foo.com>:
|
832
|
+
sub:r:1024:1:097A79EB1F7D4619:1342810387::::::e:
|
833
|
+
sub:r:1024:1:39093E8E9057625E:1342810404::::::e:
|
834
|
+
pub:e:1024:1:31920687A8A7941B:1342810629:1342897029::-:::sc:
|
835
|
+
fpr:::::::::03B399CBC2F4B61019D14BCD31920687A8A7941B:
|
836
|
+
uid:e::::1342810629::ED8151565B25281CB92DD1E534701E660126CB0C::Backup Test <backup12@foo.com>:
|
837
|
+
sub:e:1024:1:AEF89BEE95042A0F:1342810629:1342897029:::::e:
|
838
|
+
pub:-:1024:1:E3DBAEC3FEEA03E2:1342810728:::-:::scSC:
|
839
|
+
fpr:::::::::444B0870D985CF70BBB7F4DCE3DBAEC3FEEA03E2:
|
840
|
+
uid:-::::1342810796::4D1B8CC29335BF79232CA71210F75CF80318B06A::Backup Test <backup13@foo.com>:
|
841
|
+
uid:-::::1342810728::F1422363E8DC1EC3076906505CE66855BB44CAB7::Backup Test <backup14@foo.com>:
|
842
|
+
sub:e:1024:1:C95DED316504D17C:1342810728:1342897218:::::e:
|
843
|
+
pub:u:1024:1:027B83DB8A82B9CB:1343402840:::u:::scESC:
|
844
|
+
fpr:::::::::A20D90150CE4E5F851AD3A9D027B83DB8A82B9CB:
|
845
|
+
uid:u::::1343402840::307F1E025E8BEB7DABCADC353291184AD493A28E::Backup Test <backup01@foo.com>:
|
846
|
+
sub:u:1024:1:EF31D36414FD8B2B:1343402840::::::e:
|
847
|
+
pub:u:1024:1:4CEA6442A4A57A76:1343402867:::u:::scESC:
|
848
|
+
fpr:::::::::5742EAFB4CF38014B474671E4CEA6442A4A57A76:
|
849
|
+
uid:u::::1343402932::C220D9FF5C9652AA31D3CE0487D88EFF291FA1ED::Backup Test:
|
850
|
+
uid:u::::1343402922::E89778553F703C26517AD8321C17C81F3213A782::Backup Test <backup02@foo.com>:
|
851
|
+
sub:u:1024:1:140DDC2E97DA3567:1343402867::::::e:
|
852
|
+
EOS
|
853
|
+
}
|
854
|
+
|
855
|
+
let(:valid_identifiers) {
|
856
|
+
%w{ FF9CFEA6 5EFD157FFF9CFEA6 72E56E48E362BB402B3344045EFD157FFF9CFEA6
|
857
|
+
1E3DA3E8 570CE9221E3DA3E8 616BBC8409C1AED791F8E6F8570CE9221E3DA3E8
|
858
|
+
<backup04@foo.com> <backup03@foo.com>
|
859
|
+
A7641A16 54F81C93A7641A16 71335B9B960CF3A3071535F454F81C93A7641A16
|
860
|
+
<backup05@foo.com>
|
861
|
+
581A88CF 0A5B6CC9581A88CF E8C459082544924B8AEA06280A5B6CC9581A88CF
|
862
|
+
<backup08@foo.com> <backup07@foo.com>
|
863
|
+
FEEA03E2 E3DBAEC3FEEA03E2 444B0870D985CF70BBB7F4DCE3DBAEC3FEEA03E2
|
864
|
+
<backup13@foo.com> <backup14@foo.com>
|
865
|
+
8A82B9CB 027B83DB8A82B9CB A20D90150CE4E5F851AD3A9D027B83DB8A82B9CB
|
866
|
+
<backup01@foo.com>
|
867
|
+
A4A57A76 4CEA6442A4A57A76 5742EAFB4CF38014B474671E4CEA6442A4A57A76
|
868
|
+
<backup02@foo.com> }
|
869
|
+
}
|
870
|
+
it 'should return an array of all valid identifiers' do
|
871
|
+
encryptor.instance_variable_set(:@system_identifiers, nil)
|
872
|
+
|
873
|
+
encryptor.expects(:utility).with(:gpg).returns('gpg')
|
874
|
+
encryptor.expects(:base_options).returns("--base 'options'")
|
875
|
+
encryptor.expects(:run).with(
|
876
|
+
"gpg --base 'options' --with-colons --fixed-list-mode --fingerprint"
|
877
|
+
).returns(gpg_output)
|
878
|
+
|
879
|
+
encryptor.send(:system_identifiers).should == valid_identifiers
|
880
|
+
# results cached
|
881
|
+
encryptor.send(:system_identifiers).should == valid_identifiers
|
882
|
+
encryptor.instance_variable_get(:@system_identifiers).
|
883
|
+
should == valid_identifiers
|
884
|
+
end
|
885
|
+
end # describe '#system_identifiers'
|
886
|
+
|
887
|
+
describe 'deprecations' do
|
888
|
+
describe '#key' do
|
889
|
+
it 'should import #key, use identifier for #recipients and log a warning' do
|
890
|
+
encryptor.expects(:import_key).
|
891
|
+
with('deprecated :key', 'a public key').
|
892
|
+
returns('an_identifier')
|
893
|
+
|
894
|
+
Backup::Logger.expects(:warn).with {|err|
|
895
|
+
err.should be_an_instance_of(Backup::Errors::ConfigurationError)
|
896
|
+
err.message.should match(
|
897
|
+
"GPG#key has been deprecated as of backup v.3.0.26"
|
898
|
+
)
|
899
|
+
err.message.should match(
|
900
|
+
"replaced with #keys and #recipients"
|
901
|
+
)
|
902
|
+
}
|
903
|
+
|
904
|
+
encryptor.key = 'a public key'
|
905
|
+
encryptor.recipients.should == 'an_identifier'
|
906
|
+
end
|
907
|
+
end # describe '#key'
|
908
|
+
end # describe 'deprecations'
|
150
909
|
end
|