imap-backup 2.2.2 → 3.2.1

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +51 -0
  3. data/.rubocop.yml +2 -2
  4. data/.rubocop_todo.yml +10 -26
  5. data/README.md +6 -13
  6. data/bin/imap-backup +4 -1
  7. data/docs/01-credentials-screen.png +0 -0
  8. data/docs/02-new-project.png +0 -0
  9. data/docs/03-initial-credentials-for-project.png +0 -0
  10. data/docs/04-credential-type-selection.png +0 -0
  11. data/docs/05-cant-create-without-consent-setup.png +0 -0
  12. data/docs/06-user-type-selection.png +0 -0
  13. data/docs/07-consent-screen-form.png +0 -0
  14. data/docs/08-app-scopes.png +0 -0
  15. data/docs/09-scope-selection.png +0 -0
  16. data/docs/10-updated-app-scopes.png +0 -0
  17. data/docs/11-test-users.png +0 -0
  18. data/docs/12-add-users.png +0 -0
  19. data/docs/13-create-oauth-client.png +0 -0
  20. data/docs/14-application-details.png +0 -0
  21. data/docs/16-initial-menu.png +0 -0
  22. data/docs/17-inputting-the-email-address.png +0 -0
  23. data/docs/18-choose-password.png +0 -0
  24. data/docs/19-supply-client-info.png +0 -0
  25. data/docs/20-choose-gmail-account.png +0 -0
  26. data/docs/21-accept-warnings.png +0 -0
  27. data/docs/22-grant-access.png +0 -0
  28. data/docs/24-confirm-choices.png +0 -0
  29. data/docs/25-success-code.png +0 -0
  30. data/docs/26-type-code-into-imap-backup.png +0 -0
  31. data/docs/27-success.png +0 -0
  32. data/docs/setting-up-gmail.md +166 -0
  33. data/imap-backup.gemspec +3 -8
  34. data/lib/email/mboxrd/message.rb +2 -0
  35. data/lib/email/provider.rb +3 -1
  36. data/lib/gmail/authenticator.rb +160 -0
  37. data/lib/google/auth/stores/in_memory_token_store.rb +9 -0
  38. data/lib/imap/backup.rb +2 -1
  39. data/lib/imap/backup/account/connection.rb +67 -35
  40. data/lib/imap/backup/account/folder.rb +18 -6
  41. data/lib/imap/backup/configuration/account.rb +9 -1
  42. data/lib/imap/backup/configuration/folder_chooser.rb +14 -15
  43. data/lib/imap/backup/configuration/gmail_oauth2.rb +82 -0
  44. data/lib/imap/backup/configuration/setup.rb +4 -1
  45. data/lib/imap/backup/configuration/store.rb +12 -12
  46. data/lib/imap/backup/serializer/mbox_store.rb +2 -2
  47. data/lib/imap/backup/version.rb +4 -3
  48. data/lib/retry_on_error.rb +14 -0
  49. data/spec/features/backup_spec.rb +1 -1
  50. data/spec/fixtures/connection.yml +1 -1
  51. data/spec/support/fixtures.rb +7 -2
  52. data/spec/unit/gmail/authenticator_spec.rb +138 -0
  53. data/spec/unit/google/auth/stores/in_memory_token_store_spec.rb +15 -0
  54. data/spec/unit/imap/backup/account/connection_spec.rb +146 -53
  55. data/spec/unit/imap/backup/account/folder_spec.rb +42 -10
  56. data/spec/unit/imap/backup/configuration/account_spec.rb +37 -24
  57. data/spec/unit/imap/backup/configuration/folder_chooser_spec.rb +7 -13
  58. data/spec/unit/imap/backup/configuration/gmail_oauth2_spec.rb +84 -0
  59. data/spec/unit/imap/backup/configuration/setup_spec.rb +51 -31
  60. metadata +83 -9
  61. data/.travis.yml +0 -25
@@ -6,11 +6,11 @@ describe Imap::Backup::Configuration::FolderChooser do
6
6
 
7
7
  let(:connection) do
8
8
  instance_double(
9
- Imap::Backup::Account::Connection, folders: remote_folders
9
+ Imap::Backup::Account::Connection, folders: connection_folders
10
10
  )
11
11
  end
12
12
  let(:account) { {folders: []} }
13
- let(:remote_folders) { [] }
13
+ let(:connection_folders) { [] }
14
14
  let!(:highline_streams) { prepare_highline }
15
15
  let(:input) { highline_streams[0] }
16
16
  let(:output) { highline_streams[1] }
@@ -37,15 +37,9 @@ describe Imap::Backup::Configuration::FolderChooser do
37
37
 
38
38
  describe "folder listing" do
39
39
  let(:account) { {folders: [{name: "my_folder"}]} }
40
- let(:remote_folders) do
41
- # this one is already backed up:
42
- folder1 = instance_double(
43
- Imap::Backup::Account::Folder, name: "my_folder"
44
- )
45
- folder2 = instance_double(
46
- Imap::Backup::Account::Folder, name: "another_folder"
47
- )
48
- [folder1, folder2]
40
+ let(:connection_folders) do
41
+ # N.B. my_folder is already backed up
42
+ %w(my_folder another_folder)
49
43
  end
50
44
 
51
45
  describe "display" do
@@ -93,7 +87,7 @@ describe Imap::Backup::Configuration::FolderChooser do
93
87
  let(:account) do
94
88
  {folders: [{name: "on_server"}, {name: "not_on_server"}]}
95
89
  end
96
- let(:remote_folders) do
90
+ let(:connection_folders) do
97
91
  [
98
92
  instance_double(Imap::Backup::Account::Folder, name: "on_server")
99
93
  ]
@@ -112,7 +106,7 @@ describe Imap::Backup::Configuration::FolderChooser do
112
106
  end
113
107
 
114
108
  context "when folders are not available" do
115
- let(:remote_folders) { nil }
109
+ let(:connection_folders) { nil }
116
110
 
117
111
  before do
118
112
  allow(Imap::Backup::Configuration::Setup.highline).
@@ -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.2.1
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-02-17 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
@@ -94,6 +122,20 @@ dependencies:
94
122
  - - ">="
95
123
  - !ruby/object:Gem::Version
96
124
  version: 3.0.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec_junit_formatter
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
97
139
  - !ruby/object:Gem::Dependency
98
140
  name: rubocop-rspec
99
141
  requirement: !ruby/object:Gem::Requirement
@@ -130,22 +172,50 @@ executables:
130
172
  extensions: []
131
173
  extra_rdoc_files: []
132
174
  files:
175
+ - ".circleci/config.yml"
133
176
  - ".gitignore"
134
177
  - ".rspec"
135
178
  - ".rspec-all"
136
179
  - ".rubocop.yml"
137
180
  - ".rubocop_todo.yml"
138
- - ".travis.yml"
139
181
  - Gemfile
140
182
  - LICENSE
141
183
  - README.md
142
184
  - Rakefile
143
185
  - bin/imap-backup
144
186
  - docker-compose.yml
187
+ - docs/01-credentials-screen.png
188
+ - docs/02-new-project.png
189
+ - docs/03-initial-credentials-for-project.png
190
+ - docs/04-credential-type-selection.png
191
+ - docs/05-cant-create-without-consent-setup.png
192
+ - docs/06-user-type-selection.png
193
+ - docs/07-consent-screen-form.png
194
+ - docs/08-app-scopes.png
195
+ - docs/09-scope-selection.png
196
+ - docs/10-updated-app-scopes.png
197
+ - docs/11-test-users.png
198
+ - docs/12-add-users.png
199
+ - docs/13-create-oauth-client.png
200
+ - docs/14-application-details.png
201
+ - docs/16-initial-menu.png
202
+ - docs/17-inputting-the-email-address.png
203
+ - docs/18-choose-password.png
204
+ - docs/19-supply-client-info.png
205
+ - docs/20-choose-gmail-account.png
206
+ - docs/21-accept-warnings.png
207
+ - docs/22-grant-access.png
208
+ - docs/24-confirm-choices.png
209
+ - docs/25-success-code.png
210
+ - docs/26-type-code-into-imap-backup.png
211
+ - docs/27-success.png
145
212
  - docs/docker-imap.md
213
+ - docs/setting-up-gmail.md
146
214
  - imap-backup.gemspec
147
215
  - lib/email/mboxrd/message.rb
148
216
  - lib/email/provider.rb
217
+ - lib/gmail/authenticator.rb
218
+ - lib/google/auth/stores/in_memory_token_store.rb
149
219
  - lib/imap/backup.rb
150
220
  - lib/imap/backup/account/connection.rb
151
221
  - lib/imap/backup/account/folder.rb
@@ -153,6 +223,7 @@ files:
153
223
  - lib/imap/backup/configuration/asker.rb
154
224
  - lib/imap/backup/configuration/connection_tester.rb
155
225
  - lib/imap/backup/configuration/folder_chooser.rb
226
+ - lib/imap/backup/configuration/gmail_oauth2.rb
156
227
  - lib/imap/backup/configuration/list.rb
157
228
  - lib/imap/backup/configuration/setup.rb
158
229
  - lib/imap/backup/configuration/store.rb
@@ -164,6 +235,7 @@ files:
164
235
  - lib/imap/backup/uploader.rb
165
236
  - lib/imap/backup/utils.rb
166
237
  - lib/imap/backup/version.rb
238
+ - lib/retry_on_error.rb
167
239
  - spec/features/backup_spec.rb
168
240
  - spec/features/helper.rb
169
241
  - spec/features/restore_spec.rb
@@ -180,12 +252,15 @@ files:
180
252
  - spec/support/silence_logging.rb
181
253
  - spec/unit/email/mboxrd/message_spec.rb
182
254
  - spec/unit/email/provider_spec.rb
255
+ - spec/unit/gmail/authenticator_spec.rb
256
+ - spec/unit/google/auth/stores/in_memory_token_store_spec.rb
183
257
  - spec/unit/imap/backup/account/connection_spec.rb
184
258
  - spec/unit/imap/backup/account/folder_spec.rb
185
259
  - spec/unit/imap/backup/configuration/account_spec.rb
186
260
  - spec/unit/imap/backup/configuration/asker_spec.rb
187
261
  - spec/unit/imap/backup/configuration/connection_tester_spec.rb
188
262
  - spec/unit/imap/backup/configuration/folder_chooser_spec.rb
263
+ - spec/unit/imap/backup/configuration/gmail_oauth2_spec.rb
189
264
  - spec/unit/imap/backup/configuration/list_spec.rb
190
265
  - spec/unit/imap/backup/configuration/setup_spec.rb
191
266
  - spec/unit/imap/backup/configuration/store_spec.rb
@@ -200,11 +275,7 @@ files:
200
275
  homepage: https://github.com/joeyates/imap-backup
201
276
  licenses: []
202
277
  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.
278
+ post_install_message:
208
279
  rdoc_options: []
209
280
  require_paths:
210
281
  - lib
@@ -219,7 +290,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
290
  - !ruby/object:Gem::Version
220
291
  version: '0'
221
292
  requirements: []
222
- rubygems_version: 3.1.2
293
+ rubygems_version: 3.0.3
223
294
  signing_key:
224
295
  specification_version: 4
225
296
  summary: Backup GMail (or other IMAP) accounts to disk
@@ -240,12 +311,15 @@ test_files:
240
311
  - spec/support/silence_logging.rb
241
312
  - spec/unit/email/mboxrd/message_spec.rb
242
313
  - spec/unit/email/provider_spec.rb
314
+ - spec/unit/gmail/authenticator_spec.rb
315
+ - spec/unit/google/auth/stores/in_memory_token_store_spec.rb
243
316
  - spec/unit/imap/backup/account/connection_spec.rb
244
317
  - spec/unit/imap/backup/account/folder_spec.rb
245
318
  - spec/unit/imap/backup/configuration/account_spec.rb
246
319
  - spec/unit/imap/backup/configuration/asker_spec.rb
247
320
  - spec/unit/imap/backup/configuration/connection_tester_spec.rb
248
321
  - spec/unit/imap/backup/configuration/folder_chooser_spec.rb
322
+ - spec/unit/imap/backup/configuration/gmail_oauth2_spec.rb
249
323
  - spec/unit/imap/backup/configuration/list_spec.rb
250
324
  - spec/unit/imap/backup/configuration/setup_spec.rb
251
325
  - spec/unit/imap/backup/configuration/store_spec.rb
data/.travis.yml DELETED
@@ -1,25 +0,0 @@
1
- language: ruby
2
-
3
- services:
4
- - docker
5
-
6
- rvm:
7
- - 2.4
8
- - 2.5
9
- - 2.6
10
- - 2.7
11
- - jruby-19mode
12
-
13
- branches:
14
- only:
15
- - master
16
-
17
- before_install:
18
- - gem update --system
19
- - gem update bundler
20
-
21
- script:
22
- - docker pull antespi/docker-imap-devel:latest
23
- - docker run -d --env MAIL_ADDRESS=address@example.org --env MAIL_PASS=pass --env MAILNAME=example.org --publish 8993:993 antespi/docker-imap-devel:latest
24
- - sleep 10
25
- - bundle exec rake