imap-backup 3.1.0 → 3.2.0
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.
- checksums.yaml +4 -4
- data/lib/imap/backup/account/connection.rb +27 -21
- data/lib/imap/backup/account/folder.rb +8 -1
- data/lib/imap/backup/configuration/store.rb +12 -12
- data/lib/imap/backup/serializer/mbox_store.rb +2 -2
- data/lib/imap/backup/version.rb +1 -1
- data/lib/retry_on_error.rb +14 -0
- data/spec/unit/imap/backup/account/connection_spec.rb +21 -2
- data/spec/unit/imap/backup/account/folder_spec.rb +19 -2
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8661c03b8bf66e47c88fb69c476105945dad6fed867c510a151d62d0c401139
|
4
|
+
data.tar.gz: 8964a8ef14fd1f8b04d23745513b3bdb8ad8283d3875bd6d559ef00e5092d1f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8da502abc6b622f9261a223001a594e5e528d4f8871d209dd14a3bfd34693415bf5317b89d3bce892b0190027579d43f5c23f106f634423cb8fbf03fb82839e9
|
7
|
+
data.tar.gz: 610d08941b592e2cbdd29b46404f1e31f83bb31c5c83f57994cbef576ab9ec31b1f11d92851fec55810242661fc31cdb0fffe0816357cfe4177c29ba7c1d3134
|
@@ -2,6 +2,7 @@ require "net/imap"
|
|
2
2
|
require "gmail_xoauth"
|
3
3
|
|
4
4
|
require "gmail/authenticator"
|
5
|
+
require "retry_on_error"
|
5
6
|
|
6
7
|
module Imap::Backup
|
7
8
|
module Account; end
|
@@ -9,6 +10,10 @@ module Imap::Backup
|
|
9
10
|
class Account::Connection
|
10
11
|
class InvalidGmailOauth2RefreshToken < StandardError; end
|
11
12
|
|
13
|
+
include RetryOnError
|
14
|
+
|
15
|
+
LOGIN_RETRY_CLASSES = [EOFError, Errno::ECONNRESET, SocketError].freeze
|
16
|
+
|
12
17
|
attr_reader :connection_options
|
13
18
|
attr_reader :local_path
|
14
19
|
attr_reader :password
|
@@ -79,26 +84,27 @@ module Imap::Backup
|
|
79
84
|
end
|
80
85
|
|
81
86
|
def imap
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
87
|
+
@imap ||=
|
88
|
+
retry_on_error(errors: LOGIN_RETRY_CLASSES) do
|
89
|
+
options = provider_options
|
90
|
+
Imap::Backup.logger.debug(
|
91
|
+
"Creating IMAP instance: #{server}, options: #{options.inspect}"
|
92
|
+
)
|
93
|
+
imap = Net::IMAP.new(server, options)
|
94
|
+
if gmail? && Gmail::Authenticator.refresh_token?(password)
|
95
|
+
authenticator = Gmail::Authenticator.new(email: username, token: password)
|
96
|
+
credentials = authenticator.credentials
|
97
|
+
raise InvalidGmailOauth2RefreshToken if !credentials
|
98
|
+
|
99
|
+
Imap::Backup.logger.debug "Logging in with OAuth2 token: #{username}"
|
100
|
+
imap.authenticate("XOAUTH2", username, credentials.access_token)
|
101
|
+
else
|
102
|
+
Imap::Backup.logger.debug "Logging in: #{username}/#{masked_password}"
|
103
|
+
imap.login(username, password)
|
104
|
+
end
|
105
|
+
Imap::Backup.logger.debug "Login complete"
|
106
|
+
imap
|
107
|
+
end
|
102
108
|
end
|
103
109
|
|
104
110
|
def server
|
@@ -175,7 +181,7 @@ module Imap::Backup
|
|
175
181
|
def backup_folders
|
176
182
|
@backup_folders ||=
|
177
183
|
begin
|
178
|
-
if @config_folders
|
184
|
+
if @config_folders&.any?
|
179
185
|
@config_folders
|
180
186
|
else
|
181
187
|
folders.map { |name| {name: name} }
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require "forwardable"
|
2
2
|
|
3
|
+
require "retry_on_error"
|
4
|
+
|
3
5
|
module Imap::Backup
|
4
6
|
module Account; end
|
5
7
|
|
@@ -7,8 +9,10 @@ module Imap::Backup
|
|
7
9
|
|
8
10
|
class Account::Folder
|
9
11
|
extend Forwardable
|
12
|
+
include RetryOnError
|
10
13
|
|
11
14
|
REQUESTED_ATTRIBUTES = %w[RFC822 FLAGS INTERNALDATE].freeze
|
15
|
+
UID_FETCH_RETRY_CLASSES = [EOFError].freeze
|
12
16
|
|
13
17
|
attr_reader :connection
|
14
18
|
attr_reader :name
|
@@ -66,7 +70,10 @@ module Imap::Backup
|
|
66
70
|
|
67
71
|
def fetch(uid)
|
68
72
|
examine
|
69
|
-
fetch_data_items =
|
73
|
+
fetch_data_items =
|
74
|
+
retry_on_error(errors: UID_FETCH_RETRY_CLASSES) do
|
75
|
+
imap.uid_fetch([uid.to_i], REQUESTED_ATTRIBUTES)
|
76
|
+
end
|
70
77
|
return nil if fetch_data_items.nil?
|
71
78
|
|
72
79
|
fetch_data_item = fetch_data_items[0]
|
@@ -51,18 +51,18 @@ module Imap::Backup
|
|
51
51
|
private
|
52
52
|
|
53
53
|
def data
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
54
|
+
@data ||=
|
55
|
+
begin
|
56
|
+
if File.exist?(pathname)
|
57
|
+
Utils.check_permissions pathname, 0o600
|
58
|
+
contents = File.read(pathname)
|
59
|
+
data = JSON.parse(contents, symbolize_names: true)
|
60
|
+
else
|
61
|
+
data = {accounts: []}
|
62
|
+
end
|
63
|
+
data[:debug] = data.key?(:debug) ? data[:debug] == true : false
|
64
|
+
data
|
65
|
+
end
|
66
66
|
end
|
67
67
|
|
68
68
|
def remove_modified_flags
|
@@ -161,7 +161,7 @@ module Imap::Backup
|
|
161
161
|
def load_nth(index)
|
162
162
|
enumerator = Serializer::MboxEnumerator.new(mbox_pathname)
|
163
163
|
enumerator.each.with_index do |raw, i|
|
164
|
-
next
|
164
|
+
next if i != index
|
165
165
|
|
166
166
|
return Email::Mboxrd::Message.from_serialized(raw)
|
167
167
|
end
|
@@ -169,7 +169,7 @@ module Imap::Backup
|
|
169
169
|
end
|
170
170
|
|
171
171
|
def imap_looks_like_json?
|
172
|
-
return false
|
172
|
+
return false if !imap_exist?
|
173
173
|
|
174
174
|
content = File.read(imap_pathname)
|
175
175
|
content.start_with?("{")
|
data/lib/imap/backup/version.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
module RetryOnError
|
2
|
+
def retry_on_error(errors:, limit: 10)
|
3
|
+
tries ||= 1
|
4
|
+
yield
|
5
|
+
rescue *errors => e
|
6
|
+
if tries < limit
|
7
|
+
message = "#{e}, attempt #{tries} of #{limit}"
|
8
|
+
Imap::Backup.logger.debug message
|
9
|
+
tries += 1
|
10
|
+
retry
|
11
|
+
end
|
12
|
+
raise e
|
13
|
+
end
|
14
|
+
end
|
@@ -77,13 +77,15 @@ describe Imap::Backup::Account::Connection do
|
|
77
77
|
end
|
78
78
|
|
79
79
|
describe "#imap" do
|
80
|
-
let
|
80
|
+
let(:result) { subject.imap }
|
81
81
|
|
82
82
|
it "returns the IMAP connection" do
|
83
83
|
expect(result).to eq(imap)
|
84
84
|
end
|
85
85
|
|
86
86
|
it "uses the password" do
|
87
|
+
result
|
88
|
+
|
87
89
|
expect(imap).to have_received(:login).with(USERNAME, PASSWORD)
|
88
90
|
end
|
89
91
|
|
@@ -138,7 +140,24 @@ describe Imap::Backup::Account::Connection do
|
|
138
140
|
end
|
139
141
|
end
|
140
142
|
|
141
|
-
|
143
|
+
context "when the first login attempt fails" do
|
144
|
+
before do
|
145
|
+
outcomes = [-> { raise EOFError }, -> { true }]
|
146
|
+
allow(imap).to receive(:login) { outcomes.shift.call }
|
147
|
+
end
|
148
|
+
|
149
|
+
it "retries" do
|
150
|
+
subject.imap
|
151
|
+
|
152
|
+
expect(imap).to have_received(:login).twice
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "when run" do
|
157
|
+
before { subject.imap }
|
158
|
+
|
159
|
+
include_examples "connects to IMAP"
|
160
|
+
end
|
142
161
|
end
|
143
162
|
|
144
163
|
describe "#folders" do
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# rubocop:disable RSpec/PredicateMatcher
|
2
2
|
|
3
3
|
describe Imap::Backup::Account::Folder do
|
4
|
-
FOLDER_NAME = "Gelöscht"
|
5
|
-
ENCODED_FOLDER_NAME = "Gel&APY-scht"
|
4
|
+
FOLDER_NAME = "Gelöscht".freeze
|
5
|
+
ENCODED_FOLDER_NAME = "Gel&APY-scht".freeze
|
6
6
|
|
7
7
|
subject { described_class.new(connection, FOLDER_NAME) }
|
8
8
|
|
@@ -103,6 +103,23 @@ describe Imap::Backup::Account::Folder do
|
|
103
103
|
expect(subject.fetch(123)).to be_nil
|
104
104
|
end
|
105
105
|
end
|
106
|
+
|
107
|
+
context "when the first fetch_uid attempts fail" do
|
108
|
+
before do
|
109
|
+
outcomes = [-> { raise EOFError }, -> { [fetch_data_item] }]
|
110
|
+
allow(imap).to receive(:uid_fetch) { outcomes.shift.call }
|
111
|
+
end
|
112
|
+
|
113
|
+
it "retries" do
|
114
|
+
subject.fetch(123)
|
115
|
+
|
116
|
+
expect(imap).to have_received(:uid_fetch).twice
|
117
|
+
end
|
118
|
+
|
119
|
+
it "succeeds" do
|
120
|
+
subject.fetch(123)
|
121
|
+
end
|
122
|
+
end
|
106
123
|
end
|
107
124
|
|
108
125
|
describe "#folder" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: imap-backup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Yates
|
@@ -221,6 +221,7 @@ files:
|
|
221
221
|
- lib/imap/backup/uploader.rb
|
222
222
|
- lib/imap/backup/utils.rb
|
223
223
|
- lib/imap/backup/version.rb
|
224
|
+
- lib/retry_on_error.rb
|
224
225
|
- spec/features/backup_spec.rb
|
225
226
|
- spec/features/helper.rb
|
226
227
|
- spec/features/restore_spec.rb
|