imap-backup 2.2.2 → 3.0.0.rc1

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.
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