imap-backup 2.2.2 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -2
  3. data/.rubocop_todo.yml +10 -26
  4. data/README.md +4 -11
  5. data/bin/imap-backup +3 -0
  6. data/docs/01-credentials-screen.png +0 -0
  7. data/docs/02-new-project.png +0 -0
  8. data/docs/03-initial-credentials-for-project.png +0 -0
  9. data/docs/04-credential-type-selection.png +0 -0
  10. data/docs/05-cant-create-without-consent-setup.png +0 -0
  11. data/docs/06-user-type-selection.png +0 -0
  12. data/docs/07-consent-screen-form.png +0 -0
  13. data/docs/08-app-scopes.png +0 -0
  14. data/docs/09-scope-selection.png +0 -0
  15. data/docs/10-updated-app-scopes.png +0 -0
  16. data/docs/11-test-users.png +0 -0
  17. data/docs/12-add-users.png +0 -0
  18. data/docs/13-create-oauth-client.png +0 -0
  19. data/docs/14-application-details.png +0 -0
  20. data/docs/16-initial-menu.png +0 -0
  21. data/docs/17-inputting-the-email-address.png +0 -0
  22. data/docs/18-choose-password.png +0 -0
  23. data/docs/19-supply-client-info.png +0 -0
  24. data/docs/20-choose-gmail-account.png +0 -0
  25. data/docs/21-accept-warnings.png +0 -0
  26. data/docs/22-grant-access.png +0 -0
  27. data/docs/24-confirm-choices.png +0 -0
  28. data/docs/25-success-code.png +0 -0
  29. data/docs/26-type-code-into-imap-backup.png +0 -0
  30. data/docs/27-success.png +0 -0
  31. data/docs/setting-up-gmail.md +166 -0
  32. data/imap-backup.gemspec +2 -8
  33. data/lib/email/mboxrd/message.rb +2 -0
  34. data/lib/email/provider.rb +3 -1
  35. data/lib/gmail/authenticator.rb +160 -0
  36. data/lib/google/auth/stores/in_memory_token_store.rb +9 -0
  37. data/lib/imap/backup.rb +2 -1
  38. data/lib/imap/backup/account/connection.rb +31 -13
  39. data/lib/imap/backup/configuration/account.rb +9 -1
  40. data/lib/imap/backup/configuration/gmail_oauth2.rb +82 -0
  41. data/lib/imap/backup/configuration/setup.rb +4 -1
  42. data/lib/imap/backup/version.rb +5 -4
  43. data/spec/features/backup_spec.rb +1 -1
  44. data/spec/unit/gmail/authenticator_spec.rb +138 -0
  45. data/spec/unit/google/auth/stores/in_memory_token_store_spec.rb +15 -0
  46. data/spec/unit/imap/backup/account/connection_spec.rb +103 -40
  47. data/spec/unit/imap/backup/configuration/account_spec.rb +37 -24
  48. data/spec/unit/imap/backup/configuration/gmail_oauth2_spec.rb +84 -0
  49. data/spec/unit/imap/backup/configuration/setup_spec.rb +51 -31
  50. metadata +68 -9
@@ -1,13 +1,16 @@
1
- # rubocop:disable RSpec/NestedGroups
2
-
3
1
  describe Imap::Backup::Configuration::Account do
4
- describe "#initialize" do
5
- subject { described_class.new(store, account, highline) }
2
+ ACCOUNT = "account".freeze
3
+ GMAIL_IMAP_SERVER = "imap.gmail.com".freeze
4
+ HIGHLINE = "highline".freeze
5
+ STORE = "store".freeze
6
+
7
+ subject { described_class.new(store, account, highline) }
6
8
 
7
- let(:store) { "store" }
8
- let(:account) { "account" }
9
- let(:highline) { "highline" }
9
+ let(:account) { ACCOUNT }
10
+ let(:highline) { HIGHLINE }
11
+ let(:store) { STORE }
10
12
 
13
+ describe "#initialize" do
11
14
  [:store, :account, :highline].each do |param|
12
15
  it "expects #{param}" do
13
16
  expect(subject.send(param)).to eq(send(param))
@@ -16,8 +19,6 @@ describe Imap::Backup::Configuration::Account do
16
19
  end
17
20
 
18
21
  describe "#run" do
19
- subject { described_class.new(store, account, highline) }
20
-
21
22
  let(:highline_menu_class) do
22
23
  Class.new do
23
24
  attr_reader :choices
@@ -46,7 +47,7 @@ describe Imap::Backup::Configuration::Account do
46
47
  let(:account) do
47
48
  {
48
49
  username: existing_email,
49
- server: existing_server,
50
+ server: current_server,
50
51
  local_path: "/backup/path",
51
52
  folders: [{name: "my_folder"}],
52
53
  password: existing_password
@@ -60,7 +61,7 @@ describe Imap::Backup::Configuration::Account do
60
61
  end
61
62
  let(:existing_email) { "user@example.com" }
62
63
  let(:new_email) { "foo@example.com" }
63
- let(:existing_server) { "imap.example.com" }
64
+ let(:current_server) { "imap.example.com" }
64
65
  let(:existing_password) { "password" }
65
66
  let(:other_email) { "other@example.com" }
66
67
  let(:other_existing_path) { "/other/existing/path" }
@@ -136,7 +137,7 @@ describe Imap::Backup::Configuration::Account do
136
137
  end
137
138
  end
138
139
 
139
- describe "email" do
140
+ describe "choosing 'modify email'" do
140
141
  before do
141
142
  allow(Imap::Backup::Configuration::Asker).
142
143
  to receive(:email) { new_email }
@@ -146,7 +147,7 @@ describe Imap::Backup::Configuration::Account do
146
147
 
147
148
  context "when the server is blank" do
148
149
  [
149
- ["GMail", "foo@gmail.com", "imap.gmail.com"],
150
+ ["GMail", "foo@gmail.com", GMAIL_IMAP_SERVER],
150
151
  ["Fastmail", "bar@fastmail.fm", "imap.fastmail.com"],
151
152
  ["Fastmail", "bar@fastmail.com", "imap.fastmail.com"]
152
153
  ].each do |service, email, expected|
@@ -154,7 +155,7 @@ describe Imap::Backup::Configuration::Account do
154
155
  let(:new_email) { email }
155
156
 
156
157
  context "with nil" do
157
- let(:existing_server) { nil }
158
+ let(:current_server) { nil }
158
159
 
159
160
  it "sets a default server" do
160
161
  expect(account[:server]).to eq(expected)
@@ -162,7 +163,7 @@ describe Imap::Backup::Configuration::Account do
162
163
  end
163
164
 
164
165
  context "with an empty string" do
165
- let(:existing_server) { "" }
166
+ let(:current_server) { "" }
166
167
 
167
168
  it "sets a default server" do
168
169
  expect(account[:server]).to eq(expected)
@@ -172,7 +173,7 @@ describe Imap::Backup::Configuration::Account do
172
173
  end
173
174
 
174
175
  context "when the domain is unrecognized" do
175
- let(:existing_server) { nil }
176
+ let(:current_server) { nil }
176
177
  let(:provider) do
177
178
  instance_double(Email::Provider, provider: :default)
178
179
  end
@@ -211,12 +212,18 @@ describe Imap::Backup::Configuration::Account do
211
212
  end
212
213
  end
213
214
 
214
- describe "password" do
215
+ describe "choosing 'modify password'" do
215
216
  let(:new_password) { "new_password" }
217
+ let(:gmail_oauth2) do
218
+ instance_double(Imap::Backup::Configuration::GmailOauth2, run: nil)
219
+ end
216
220
 
217
221
  before do
218
222
  allow(Imap::Backup::Configuration::Asker).
219
223
  to receive(:password) { new_password }
224
+ allow(Imap::Backup::Configuration::GmailOauth2).
225
+ to receive(:new).
226
+ with(account) { gmail_oauth2 }
220
227
  subject.run
221
228
  menu.choices["modify password"].call
222
229
  end
@@ -238,9 +245,17 @@ describe Imap::Backup::Configuration::Account do
238
245
 
239
246
  include_examples "it doesn't flag the account as modified"
240
247
  end
248
+
249
+ context "when the server is for GMail" do
250
+ let(:current_server) { GMAIL_IMAP_SERVER }
251
+
252
+ it "sets up GMail OAuth2" do
253
+ expect(gmail_oauth2).to have_received(:run)
254
+ end
255
+ end
241
256
  end
242
257
 
243
- describe "server" do
258
+ describe "choosing 'modify server'" do
244
259
  let(:server) { "server" }
245
260
 
246
261
  before do
@@ -258,7 +273,7 @@ describe Imap::Backup::Configuration::Account do
258
273
  include_examples "it flags the account as modified"
259
274
  end
260
275
 
261
- describe "backup_path" do
276
+ describe "choosing 'modify backup path'" do
262
277
  let(:new_backup_path) { "/new/path" }
263
278
 
264
279
  before do
@@ -296,7 +311,7 @@ describe Imap::Backup::Configuration::Account do
296
311
  include_examples "it flags the account as modified"
297
312
  end
298
313
 
299
- describe "folders" do
314
+ describe "choosing 'choose backup folders'" do
300
315
  let(:chooser) do
301
316
  instance_double(Imap::Backup::Configuration::FolderChooser, run: nil)
302
317
  end
@@ -313,7 +328,7 @@ describe Imap::Backup::Configuration::Account do
313
328
  end
314
329
  end
315
330
 
316
- describe "connection test" do
331
+ describe "choosing 'test connection'" do
317
332
  before do
318
333
  allow(Imap::Backup::Configuration::ConnectionTester).
319
334
  to receive(:test) { "All fine" }
@@ -328,7 +343,7 @@ describe Imap::Backup::Configuration::Account do
328
343
  end
329
344
  end
330
345
 
331
- describe "deletion" do
346
+ describe "choosing 'delete'" do
332
347
  let(:confirmed) { true }
333
348
 
334
349
  before do
@@ -355,5 +370,3 @@ describe Imap::Backup::Configuration::Account do
355
370
  end
356
371
  end
357
372
  end
358
-
359
- # rubocop:enable RSpec/NestedGroups
@@ -0,0 +1,84 @@
1
+ describe Imap::Backup::Configuration::GmailOauth2 do
2
+ include HighLineTestHelpers
3
+
4
+ subject { described_class.new(account) }
5
+
6
+ let(:authorization_url) { "some long authorization_url" }
7
+ let(:credentials) { "credentials" }
8
+ let(:json_token) { '{"sentinel":"foo"}' }
9
+ let!(:highline_streams) { prepare_highline }
10
+ let(:highline) { Imap::Backup::Configuration::Setup.highline }
11
+ let(:input) { highline_streams[0] }
12
+ let(:output) { highline_streams[1] }
13
+ let(:account) { {} }
14
+
15
+ let(:authorizer) do
16
+ instance_double(
17
+ Google::Auth::UserAuthorizer,
18
+ get_authorization_url: authorization_url,
19
+ get_and_store_credentials_from_code: credentials
20
+ )
21
+ end
22
+ let(:token_store) do
23
+ instance_double(
24
+ Google::Auth::Stores::InMemoryTokenStore,
25
+ load: json_token
26
+ )
27
+ end
28
+
29
+ before do
30
+ allow(Google::Auth::UserAuthorizer).
31
+ to receive(:new) { authorizer }
32
+ allow(Google::Auth::Stores::InMemoryTokenStore).
33
+ to receive(:new) { token_store }
34
+
35
+ allow(highline).to receive(:ask).and_call_original
36
+
37
+ allow(Kernel).to receive(:system)
38
+ allow(Kernel).to receive(:puts)
39
+
40
+ allow(input).to receive(:gets).and_return(
41
+ "my_client_id\n",
42
+ "my_secret\n",
43
+ "my_code\n"
44
+ )
45
+ end
46
+
47
+ describe "#run" do
48
+ let!(:result) { subject.run }
49
+
50
+ it "clears the screen" do
51
+ expect(Kernel).to have_received(:system).with("clear")
52
+ end
53
+
54
+ it "requests client_id" do
55
+ expect(highline).to have_received(:ask).with("client_id: ")
56
+ end
57
+
58
+ it "requests client_secret" do
59
+ expect(highline).to have_received(:ask).with("client_secret: ")
60
+ end
61
+
62
+ it "displays the authorization URL" do
63
+ expect(Kernel).
64
+ to have_received(:puts).
65
+ with(/#{authorization_url}/)
66
+ end
67
+
68
+ it "requests the success code" do
69
+ expect(highline).to have_received(:ask).with("success code: ")
70
+ end
71
+
72
+ it "requests an access_token via the code" do
73
+ expect(authorizer).to have_received(:get_and_store_credentials_from_code)
74
+ end
75
+
76
+ it "returns the credentials" do
77
+ expect(result).to match('"sentinel":"foo"')
78
+ end
79
+
80
+ it "includes the client_secret in the credentials" do
81
+ expect(result).to match('"client_secret":"my_secret"')
82
+ end
83
+ end
84
+ end
@@ -1,8 +1,28 @@
1
- # rubocop:disable RSpec/NestedGroups
2
-
3
1
  describe Imap::Backup::Configuration::Setup do
4
2
  include HighLineTestHelpers
5
3
 
4
+ subject { described_class.new }
5
+
6
+ let(:normal) { {username: "account@example.com"} }
7
+ let(:accounts) { [normal] }
8
+ let(:store) do
9
+ instance_double(
10
+ Imap::Backup::Configuration::Store,
11
+ "accounts": accounts,
12
+ "path": "/base/path",
13
+ "save": nil,
14
+ "debug?": debug,
15
+ "debug=": nil,
16
+ "modified?": modified
17
+ )
18
+ end
19
+ let(:debug) { false }
20
+ let(:modified) { false }
21
+ let!(:highline_streams) { prepare_highline }
22
+ let(:input) { highline_streams[0] }
23
+ let(:output) { highline_streams[1] }
24
+ let(:gmail_imap_server) { "imap.gmail.com" }
25
+
6
26
  describe "#initialize" do
7
27
  context "without a config file" do
8
28
  it "works" do
@@ -12,27 +32,6 @@ describe Imap::Backup::Configuration::Setup do
12
32
  end
13
33
 
14
34
  describe "#run" do
15
- subject { described_class.new }
16
-
17
- let(:normal) { {username: "account@example.com"} }
18
- let(:accounts) { [normal] }
19
- let(:store) do
20
- instance_double(
21
- Imap::Backup::Configuration::Store,
22
- "accounts": accounts,
23
- "path": "/base/path",
24
- "save": nil,
25
- "debug?": debug,
26
- "debug=": nil,
27
- "modified?": modified
28
- )
29
- end
30
- let(:debug) { false }
31
- let(:modified) { false }
32
- let!(:highline_streams) { prepare_highline }
33
- let(:input) { highline_streams[0] }
34
- let(:output) { highline_streams[1] }
35
-
36
35
  before do
37
36
  allow(Imap::Backup::Configuration::Store).to receive(:new) { store }
38
37
  allow(Imap::Backup).to receive(:setup_logging)
@@ -112,28 +111,51 @@ describe Imap::Backup::Configuration::Setup do
112
111
  context "when adding accounts" do
113
112
  let(:blank_account) do
114
113
  {
115
- username: "new@example.com",
114
+ username: added_email,
116
115
  password: "",
117
- local_path: "/base/path/new_example.com",
116
+ local_path: local_path,
118
117
  folders: []
119
118
  }
120
119
  end
121
120
  let(:account) do
122
121
  instance_double(Imap::Backup::Configuration::Account, run: nil)
123
122
  end
123
+ let(:added_email) { "new@example.com" }
124
+ let(:local_path) { "/base/path/new_example.com" }
124
125
 
125
126
  before do
126
127
  allow(input).to receive(:gets).and_return("add\n", "exit\n")
127
128
  allow(Imap::Backup::Configuration::Asker).to receive(:email).
128
- with(no_args) { "new@example.com" }
129
+ with(no_args) { added_email }
129
130
  allow(Imap::Backup::Configuration::Account).to receive(:new).
130
- with(store, blank_account, anything) { account }
131
+ with(store, anything, anything) { account }
131
132
 
132
133
  subject.run
133
134
  end
134
135
 
135
- it "adds account data" do
136
- expect(accounts[1]).to eq(blank_account)
136
+ it "sets username" do
137
+ expect(accounts[1][:username]).to eq(added_email)
138
+ end
139
+
140
+ it "sets blank password" do
141
+ expect(accounts[1][:password]).to eq("")
142
+ end
143
+
144
+ it "sets local_path" do
145
+ expect(accounts[1][:local_path]).to eq(local_path)
146
+ end
147
+
148
+ it "sets folders" do
149
+ expect(accounts[1][:folders]).to eq([])
150
+ end
151
+
152
+ context "when the account is a GMail account" do
153
+ let(:added_email) { "new@gmail.com" }
154
+ let(:local_path) { "/base/path/new_gmail.com" }
155
+
156
+ it "sets the server" do
157
+ expect(accounts[1][:server]).to eq(gmail_imap_server)
158
+ end
137
159
  end
138
160
 
139
161
  it "doesn't flag the unedited account as modified" do
@@ -248,5 +270,3 @@ describe Imap::Backup::Configuration::Setup do
248
270
  end
249
271
  end
250
272
  end
251
-
252
- # rubocop:enable RSpec/NestedGroups
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: imap-backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 3.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Yates
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-02 00:00:00.000000000 Z
11
+ date: 2021-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gmail_xoauth
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: googleauth
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: highline
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -142,10 +170,38 @@ files:
142
170
  - Rakefile
143
171
  - bin/imap-backup
144
172
  - docker-compose.yml
173
+ - docs/01-credentials-screen.png
174
+ - docs/02-new-project.png
175
+ - docs/03-initial-credentials-for-project.png
176
+ - docs/04-credential-type-selection.png
177
+ - docs/05-cant-create-without-consent-setup.png
178
+ - docs/06-user-type-selection.png
179
+ - docs/07-consent-screen-form.png
180
+ - docs/08-app-scopes.png
181
+ - docs/09-scope-selection.png
182
+ - docs/10-updated-app-scopes.png
183
+ - docs/11-test-users.png
184
+ - docs/12-add-users.png
185
+ - docs/13-create-oauth-client.png
186
+ - docs/14-application-details.png
187
+ - docs/16-initial-menu.png
188
+ - docs/17-inputting-the-email-address.png
189
+ - docs/18-choose-password.png
190
+ - docs/19-supply-client-info.png
191
+ - docs/20-choose-gmail-account.png
192
+ - docs/21-accept-warnings.png
193
+ - docs/22-grant-access.png
194
+ - docs/24-confirm-choices.png
195
+ - docs/25-success-code.png
196
+ - docs/26-type-code-into-imap-backup.png
197
+ - docs/27-success.png
145
198
  - docs/docker-imap.md
199
+ - docs/setting-up-gmail.md
146
200
  - imap-backup.gemspec
147
201
  - lib/email/mboxrd/message.rb
148
202
  - lib/email/provider.rb
203
+ - lib/gmail/authenticator.rb
204
+ - lib/google/auth/stores/in_memory_token_store.rb
149
205
  - lib/imap/backup.rb
150
206
  - lib/imap/backup/account/connection.rb
151
207
  - lib/imap/backup/account/folder.rb
@@ -153,6 +209,7 @@ files:
153
209
  - lib/imap/backup/configuration/asker.rb
154
210
  - lib/imap/backup/configuration/connection_tester.rb
155
211
  - lib/imap/backup/configuration/folder_chooser.rb
212
+ - lib/imap/backup/configuration/gmail_oauth2.rb
156
213
  - lib/imap/backup/configuration/list.rb
157
214
  - lib/imap/backup/configuration/setup.rb
158
215
  - lib/imap/backup/configuration/store.rb
@@ -180,12 +237,15 @@ files:
180
237
  - spec/support/silence_logging.rb
181
238
  - spec/unit/email/mboxrd/message_spec.rb
182
239
  - spec/unit/email/provider_spec.rb
240
+ - spec/unit/gmail/authenticator_spec.rb
241
+ - spec/unit/google/auth/stores/in_memory_token_store_spec.rb
183
242
  - spec/unit/imap/backup/account/connection_spec.rb
184
243
  - spec/unit/imap/backup/account/folder_spec.rb
185
244
  - spec/unit/imap/backup/configuration/account_spec.rb
186
245
  - spec/unit/imap/backup/configuration/asker_spec.rb
187
246
  - spec/unit/imap/backup/configuration/connection_tester_spec.rb
188
247
  - spec/unit/imap/backup/configuration/folder_chooser_spec.rb
248
+ - spec/unit/imap/backup/configuration/gmail_oauth2_spec.rb
189
249
  - spec/unit/imap/backup/configuration/list_spec.rb
190
250
  - spec/unit/imap/backup/configuration/setup_spec.rb
191
251
  - spec/unit/imap/backup/configuration/store_spec.rb
@@ -200,11 +260,7 @@ files:
200
260
  homepage: https://github.com/joeyates/imap-backup
201
261
  licenses: []
202
262
  metadata: {}
203
- post_install_message: |
204
- Note that, when upgrading imap-backup from version 1.x to 2.x,
205
- the metadata storage method has changed (from flat file to JSON).
206
- As a result, on the first run after an upgrade, old backup folders will be
207
- **deleted** and a full new backup created.
263
+ post_install_message:
208
264
  rdoc_options: []
209
265
  require_paths:
210
266
  - lib
@@ -215,9 +271,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
215
271
  version: 2.4.0
216
272
  required_rubygems_version: !ruby/object:Gem::Requirement
217
273
  requirements:
218
- - - ">="
274
+ - - ">"
219
275
  - !ruby/object:Gem::Version
220
- version: '0'
276
+ version: 1.3.1
221
277
  requirements: []
222
278
  rubygems_version: 3.1.2
223
279
  signing_key:
@@ -240,12 +296,15 @@ test_files:
240
296
  - spec/support/silence_logging.rb
241
297
  - spec/unit/email/mboxrd/message_spec.rb
242
298
  - spec/unit/email/provider_spec.rb
299
+ - spec/unit/gmail/authenticator_spec.rb
300
+ - spec/unit/google/auth/stores/in_memory_token_store_spec.rb
243
301
  - spec/unit/imap/backup/account/connection_spec.rb
244
302
  - spec/unit/imap/backup/account/folder_spec.rb
245
303
  - spec/unit/imap/backup/configuration/account_spec.rb
246
304
  - spec/unit/imap/backup/configuration/asker_spec.rb
247
305
  - spec/unit/imap/backup/configuration/connection_tester_spec.rb
248
306
  - spec/unit/imap/backup/configuration/folder_chooser_spec.rb
307
+ - spec/unit/imap/backup/configuration/gmail_oauth2_spec.rb
249
308
  - spec/unit/imap/backup/configuration/list_spec.rb
250
309
  - spec/unit/imap/backup/configuration/setup_spec.rb
251
310
  - spec/unit/imap/backup/configuration/store_spec.rb