imap-backup 2.2.2 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
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