net-imap 0.3.4 → 0.4.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.
Potentially problematic release.
This version of net-imap might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.github/workflows/pages.yml +46 -0
- data/.github/workflows/test.yml +12 -12
- data/Gemfile +1 -0
- data/README.md +15 -4
- data/Rakefile +0 -7
- data/benchmarks/generate_parser_benchmarks +52 -0
- data/benchmarks/parser.yml +578 -0
- data/benchmarks/stringprep.yml +1 -1
- data/lib/net/imap/authenticators.rb +26 -57
- data/lib/net/imap/command_data.rb +13 -6
- data/lib/net/imap/data_encoding.rb +3 -3
- data/lib/net/imap/deprecated_client_options.rb +139 -0
- data/lib/net/imap/response_data.rb +46 -41
- data/lib/net/imap/response_parser/parser_utils.rb +230 -0
- data/lib/net/imap/response_parser.rb +665 -627
- data/lib/net/imap/sasl/anonymous_authenticator.rb +68 -0
- data/lib/net/imap/sasl/authentication_exchange.rb +107 -0
- data/lib/net/imap/sasl/authenticators.rb +118 -0
- data/lib/net/imap/sasl/client_adapter.rb +72 -0
- data/lib/net/imap/{authenticators/cram_md5.rb → sasl/cram_md5_authenticator.rb} +15 -9
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +168 -0
- data/lib/net/imap/sasl/external_authenticator.rb +62 -0
- data/lib/net/imap/sasl/gs2_header.rb +80 -0
- data/lib/net/imap/{authenticators/login.rb → sasl/login_authenticator.rb} +19 -14
- data/lib/net/imap/sasl/oauthbearer_authenticator.rb +164 -0
- data/lib/net/imap/sasl/plain_authenticator.rb +93 -0
- data/lib/net/imap/sasl/protocol_adapters.rb +45 -0
- data/lib/net/imap/sasl/scram_algorithm.rb +58 -0
- data/lib/net/imap/sasl/scram_authenticator.rb +278 -0
- data/lib/net/imap/sasl/stringprep.rb +6 -66
- data/lib/net/imap/sasl/xoauth2_authenticator.rb +88 -0
- data/lib/net/imap/sasl.rb +144 -43
- data/lib/net/imap/sasl_adapter.rb +21 -0
- data/lib/net/imap/stringprep/nameprep.rb +70 -0
- data/lib/net/imap/stringprep/saslprep.rb +69 -0
- data/lib/net/imap/stringprep/saslprep_tables.rb +96 -0
- data/lib/net/imap/stringprep/tables.rb +146 -0
- data/lib/net/imap/stringprep/trace.rb +85 -0
- data/lib/net/imap/stringprep.rb +159 -0
- data/lib/net/imap.rb +976 -590
- data/net-imap.gemspec +2 -2
- data/rakelib/saslprep.rake +4 -4
- data/rakelib/string_prep_tables_generator.rb +82 -60
- metadata +31 -12
- data/lib/net/imap/authenticators/digest_md5.rb +0 -115
- data/lib/net/imap/authenticators/plain.rb +0 -41
- data/lib/net/imap/authenticators/xoauth2.rb +0 -20
- data/lib/net/imap/sasl/saslprep.rb +0 -55
- data/lib/net/imap/sasl/saslprep_tables.rb +0 -98
- data/lib/net/imap/sasl/stringprep_tables.rb +0 -153
data/net-imap.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.summary = %q{Ruby client api for Internet Message Access Protocol}
|
17
17
|
spec.description = %q{Ruby client api for Internet Message Access Protocol}
|
18
18
|
spec.homepage = "https://github.com/ruby/net-imap"
|
19
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
19
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.3")
|
20
20
|
spec.licenses = ["Ruby", "BSD-2-Clause"]
|
21
21
|
|
22
22
|
spec.metadata["homepage_uri"] = spec.homepage
|
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
# Specify which files should be added to the gem when it is released.
|
26
26
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
27
27
|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
28
|
-
`git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(bin|test|spec|features)/}) }
|
28
|
+
`git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(bin|test|spec|features|rfcs)/}) }
|
29
29
|
end
|
30
30
|
spec.bindir = "exe"
|
31
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
data/rakelib/saslprep.rake
CHANGED
@@ -10,17 +10,17 @@ end
|
|
10
10
|
|
11
11
|
directory "lib/net/imap/sasl"
|
12
12
|
|
13
|
-
file "lib/net/imap/
|
13
|
+
file "lib/net/imap/stringprep/tables.rb" => generator.rb_deps do |t|
|
14
14
|
File.write t.name, generator.stringprep_rb
|
15
15
|
end
|
16
16
|
|
17
|
-
file "lib/net/imap/
|
17
|
+
file "lib/net/imap/stringprep/saslprep_tables.rb" => generator.rb_deps do |t|
|
18
18
|
File.write t.name, generator.saslprep_rb
|
19
19
|
end
|
20
20
|
|
21
21
|
GENERATED_RUBY = FileList.new(
|
22
|
-
"lib/net/imap/
|
23
|
-
"lib/net/imap/
|
22
|
+
"lib/net/imap/stringprep/tables.rb",
|
23
|
+
"lib/net/imap/stringprep/saslprep_tables.rb",
|
24
24
|
)
|
25
25
|
|
26
26
|
CLEAN.include generator.clean_deps
|
@@ -62,9 +62,9 @@ class StringPrepTablesGenerator
|
|
62
62
|
# This file is generated from RFC3454, by rake. Don't edit directly.
|
63
63
|
#++
|
64
64
|
|
65
|
-
module Net::IMAP::
|
65
|
+
module Net::IMAP::StringPrep
|
66
66
|
|
67
|
-
module
|
67
|
+
module Tables
|
68
68
|
|
69
69
|
#{asgn_table "A.1"}
|
70
70
|
|
@@ -74,6 +74,12 @@ class StringPrepTablesGenerator
|
|
74
74
|
|
75
75
|
#{asgn_table "B.3"}
|
76
76
|
|
77
|
+
#{asgn_mapping "B.1", ""}
|
78
|
+
|
79
|
+
#{asgn_mapping "B.2"}
|
80
|
+
|
81
|
+
#{asgn_mapping "B.3"}
|
82
|
+
|
77
83
|
#{asgn_table "C.1.1"}
|
78
84
|
|
79
85
|
#{asgn_table "C.1.2"}
|
@@ -105,14 +111,16 @@ class StringPrepTablesGenerator
|
|
105
111
|
|
106
112
|
BIDI_DESC_REQ2 = "A string with RandALCat characters must not contain LCat characters."
|
107
113
|
|
108
|
-
# Bidirectional Characters [StringPrep, §6], Requirement 2
|
114
|
+
# Bidirectional Characters [StringPrep, §6], Requirement 2
|
115
|
+
# >>>
|
109
116
|
# If a string contains any RandALCat character, the string MUST NOT
|
110
117
|
# contain any LCat character.
|
111
118
|
BIDI_FAILS_REQ2 = #{bidi_fails_req2.inspect}.freeze
|
112
119
|
|
113
120
|
BIDI_DESC_REQ3 = "A string with RandALCat characters must start and end with RandALCat characters."
|
114
121
|
|
115
|
-
# Bidirectional Characters [StringPrep, §6], Requirement 3
|
122
|
+
# Bidirectional Characters [StringPrep, §6], Requirement 3
|
123
|
+
# >>>
|
116
124
|
# If a string contains any RandALCat character, a RandALCat
|
117
125
|
# character MUST be the first character of the string, and a
|
118
126
|
# RandALCat character MUST be the last character of the string.
|
@@ -122,15 +130,21 @@ class StringPrepTablesGenerator
|
|
122
130
|
BIDI_FAILURE = #{bidi_failure_regexp.inspect}.freeze
|
123
131
|
|
124
132
|
# Names of each codepoint table in the RFC-3454 appendices
|
125
|
-
|
133
|
+
TITLES = {
|
126
134
|
#{table_titles_rb}
|
127
135
|
}.freeze
|
128
136
|
|
129
137
|
# Regexps matching each codepoint table in the RFC-3454 appendices
|
130
|
-
|
138
|
+
REGEXPS = {
|
131
139
|
#{table_regexps_rb}
|
132
140
|
}.freeze
|
133
141
|
|
142
|
+
MAPPINGS = {
|
143
|
+
"B.1" => [IN_B_1, MAP_B_1].freeze,
|
144
|
+
"B.2" => [IN_B_2, MAP_B_2].freeze,
|
145
|
+
"B.3" => [IN_B_3, MAP_B_3].freeze,
|
146
|
+
}.freeze
|
147
|
+
|
134
148
|
end
|
135
149
|
end
|
136
150
|
RUBY
|
@@ -157,27 +171,30 @@ class StringPrepTablesGenerator
|
|
157
171
|
# This file is generated from RFC3454, by rake. Don't edit directly.
|
158
172
|
#++
|
159
173
|
|
160
|
-
module Net::IMAP::
|
174
|
+
module Net::IMAP::StringPrep
|
161
175
|
|
162
176
|
module SASLprep
|
163
177
|
|
164
178
|
# RFC4013 §2.1 Mapping - mapped to space
|
165
|
-
#
|
166
|
-
#
|
179
|
+
# >>>
|
180
|
+
# non-ASCII space characters (\\StringPrep\\[\\"C.1.2\\"]) that can
|
181
|
+
# be mapped to SPACE (U+0020)
|
167
182
|
#
|
168
183
|
# Equal to \\StringPrep\\[\\"C.1.2\\"].
|
169
|
-
# Redefined here to avoid loading
|
184
|
+
# Redefined here to avoid loading StringPrep::Tables unless necessary.
|
170
185
|
MAP_TO_SPACE = #{regex_str "C.1.2"}
|
171
186
|
|
172
187
|
# RFC4013 §2.1 Mapping - mapped to nothing
|
173
|
-
#
|
174
|
-
#
|
188
|
+
# >>>
|
189
|
+
# the "commonly mapped to nothing" characters
|
190
|
+
# (\\StringPrep\\[\\"B.1\\"]) that can be mapped to nothing.
|
175
191
|
#
|
176
192
|
# Equal to \\StringPrep\\[\\"B.1\\"].
|
177
|
-
# Redefined here to avoid loading
|
193
|
+
# Redefined here to avoid loading StringPrep::Tables unless necessary.
|
178
194
|
MAP_TO_NOTHING = #{regex_str "B.1"}
|
179
195
|
|
180
|
-
# RFC4013 §2.3 Prohibited Output
|
196
|
+
# RFC4013 §2.3 Prohibited Output
|
197
|
+
# >>>
|
181
198
|
# * Non-ASCII space characters — \\StringPrep\\[\\"C.1.2\\"]
|
182
199
|
# * ASCII control characters — \\StringPrep\\[\\"C.2.1\\"]
|
183
200
|
# * Non-ASCII control characters — \\StringPrep\\[\\"C.2.2\\"]
|
@@ -192,45 +209,52 @@ class StringPrepTablesGenerator
|
|
192
209
|
|
193
210
|
# Adds unassigned (by Unicode 3.2) codepoints to TABLES_PROHIBITED.
|
194
211
|
#
|
195
|
-
# RFC4013 §2.5 Unassigned Code Points
|
196
|
-
#
|
197
|
-
#
|
212
|
+
# RFC4013 §2.5 Unassigned Code Points
|
213
|
+
# >>>
|
214
|
+
# This profile specifies the \\StringPrep\\[\\"A.1\\"] table as its
|
215
|
+
# list of unassigned code points.
|
198
216
|
TABLES_PROHIBITED_STORED = ["A.1", *TABLES_PROHIBITED].freeze
|
199
217
|
|
200
|
-
#
|
218
|
+
# A Regexp matching codepoints prohibited by RFC4013 §2.3.
|
201
219
|
#
|
202
|
-
#
|
203
|
-
#
|
204
|
-
# Equal to +Regexp.union+ of the TABLES_PROHIBITED tables. Redefined
|
205
|
-
# here to avoid loading the StringPrep module unless necessary.
|
220
|
+
# This combines all of the TABLES_PROHIBITED tables.
|
206
221
|
PROHIBITED_OUTPUT = #{regex_str(*SASL_TABLES_PROHIBITED)}
|
207
222
|
|
208
|
-
# RFC4013 §2.5 Unassigned Code Points
|
209
|
-
#
|
210
|
-
#
|
223
|
+
# RFC4013 §2.5 Unassigned Code Points
|
224
|
+
# >>>
|
225
|
+
# This profile specifies the \\StringPrep\\[\\"A.1\\"] table as its
|
226
|
+
# list of unassigned code points.
|
227
|
+
#
|
228
|
+
# Equal to \\StringPrep\\[\\"A.1\\"].
|
229
|
+
# Redefined here to avoid loading StringPrep::Tables unless necessary.
|
211
230
|
UNASSIGNED = #{regex_str "A.1"}
|
212
231
|
|
213
|
-
#
|
232
|
+
# A Regexp matching codepoints prohibited by RFC4013 §2.3 and §2.5.
|
214
233
|
#
|
215
|
-
#
|
234
|
+
# This combines PROHIBITED_OUTPUT and UNASSIGNED.
|
216
235
|
PROHIBITED_OUTPUT_STORED = Regexp.union(
|
217
236
|
UNASSIGNED, PROHIBITED_OUTPUT
|
218
237
|
).freeze
|
219
238
|
|
220
239
|
# Bidirectional Characters [StringPrep, §6]
|
240
|
+
#
|
241
|
+
# A Regexp for strings that don't satisfy StringPrep's Bidirectional
|
242
|
+
# Characters rules.
|
243
|
+
#
|
244
|
+
# Equal to StringPrep::Tables::BIDI_FAILURE.
|
245
|
+
# Redefined here to avoid loading StringPrep::Tables unless necessary.
|
221
246
|
BIDI_FAILURE = #{bidi_failure_regexp.inspect}.freeze
|
222
247
|
|
223
|
-
#
|
248
|
+
# A Regexp matching strings prohibited by RFC4013 §2.3 and §2.4.
|
224
249
|
#
|
225
|
-
# This
|
250
|
+
# This combines PROHIBITED_OUTPUT and BIDI_FAILURE.
|
226
251
|
PROHIBITED = Regexp.union(
|
227
252
|
PROHIBITED_OUTPUT, BIDI_FAILURE,
|
228
253
|
)
|
229
254
|
|
230
|
-
#
|
255
|
+
# A Regexp matching strings prohibited by RFC4013 §2.3, §2.4, and §2.5.
|
231
256
|
#
|
232
|
-
# This
|
233
|
-
# unassigned codepoints.
|
257
|
+
# This combines PROHIBITED_OUTPUT_STORED and BIDI_FAILURE.
|
234
258
|
PROHIBITED_STORED = Regexp.union(
|
235
259
|
PROHIBITED_OUTPUT_STORED, BIDI_FAILURE,
|
236
260
|
)
|
@@ -284,6 +308,15 @@ class StringPrepTablesGenerator
|
|
284
308
|
.map{|s,e| s..(e || s)}
|
285
309
|
end
|
286
310
|
|
311
|
+
# TODO: DRY with unicode_normalize
|
312
|
+
def to_map(table)
|
313
|
+
table = table.to_hash
|
314
|
+
.transform_keys { Integer _1, 16 }
|
315
|
+
.transform_keys { [_1].pack("U*") }
|
316
|
+
.transform_values {|cps| cps.map { Integer _1, 16 } }
|
317
|
+
.transform_values { _1.pack("U*") }
|
318
|
+
end
|
319
|
+
|
287
320
|
# Starting from a codepoints array (rather than ranges) to deduplicate merged
|
288
321
|
# tables.
|
289
322
|
def to_regexp(codepoints, negate: false)
|
@@ -352,6 +385,13 @@ class StringPrepTablesGenerator
|
|
352
385
|
asgn_regex(name, regexp_for(name, negate: negate), negate: negate)
|
353
386
|
end
|
354
387
|
|
388
|
+
def asgn_mapping(name, replacement = to_map(tables[name]))
|
389
|
+
cname = name.tr(?., ?_).upcase
|
390
|
+
"# Replacements for %s\n%s%s = %p.freeze" % [
|
391
|
+
"IN_#{name}", " " * 2, "MAP_#{cname}", replacement,
|
392
|
+
]
|
393
|
+
end
|
394
|
+
|
355
395
|
def regexp_const_desc(name, negate: false)
|
356
396
|
if negate then "Matches the negation of the %s table" % [name]
|
357
397
|
else %q{%s \\StringPrep\\[\\"%s\\"]} % [titles.fetch(name), name]
|
@@ -376,40 +416,22 @@ class StringPrepTablesGenerator
|
|
376
416
|
def bidi_L ; regexp_for "D.2" end
|
377
417
|
|
378
418
|
def bidi_fails_req2
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
| # RandALCat preceded by LCat
|
384
|
-
\g<l_cat> .*? \g<r_and_al_cat>
|
385
|
-
/mux
|
419
|
+
Regexp.union(
|
420
|
+
/#{bidi_R_AL}.*?#{bidi_L}/mu, # RandALCat followed by LCat
|
421
|
+
/#{bidi_L}.*?#{bidi_R_AL}/mu, # RandALCat preceded by LCat
|
422
|
+
)
|
386
423
|
end
|
387
424
|
|
388
425
|
def bidi_fails_req3
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
\g<r_and_al_cat> .*? \g<not_r_nor_al>\z
|
395
|
-
/mux
|
426
|
+
# contains RandALCat:
|
427
|
+
Regexp.union(
|
428
|
+
/\A#{bidi_not_R_AL}.*?#{bidi_R_AL}/mu, # but doesn't start with RandALCat
|
429
|
+
/#{bidi_R_AL}.*?#{bidi_not_R_AL}\z/mu, # but doesn't end with RandALCat
|
430
|
+
)
|
396
431
|
end
|
397
432
|
|
398
|
-
# shares the bidi_R_AL definition between both req2 and req3
|
399
433
|
def bidi_failure_regexp
|
400
|
-
|
401
|
-
.gsub(%r{\(\?\<r_and_al_cat\>\(.*?\)\)}, "\g<r_and_al_cat>")
|
402
|
-
.then{|re|"(?mx-i:#{re})"}
|
403
|
-
/#{bidi_fails_req2} | #{req3_with_backref}/mux
|
404
|
-
end
|
405
|
-
|
406
|
-
def bidi_consts
|
407
|
-
<<~RUBY
|
408
|
-
#############
|
409
|
-
# Bidirectional checks.
|
410
|
-
#
|
411
|
-
|
412
|
-
RUBY
|
434
|
+
Regexp.union(bidi_fails_req2, bidi_fails_req3)
|
413
435
|
end
|
414
436
|
|
415
437
|
SASL_TABLES_PROHIBITED = %w[
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-imap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-10-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: net-protocol
|
@@ -76,33 +76,52 @@ extensions: []
|
|
76
76
|
extra_rdoc_files: []
|
77
77
|
files:
|
78
78
|
- ".github/dependabot.yml"
|
79
|
+
- ".github/workflows/pages.yml"
|
79
80
|
- ".github/workflows/test.yml"
|
80
81
|
- ".gitignore"
|
81
82
|
- Gemfile
|
82
83
|
- LICENSE.txt
|
83
84
|
- README.md
|
84
85
|
- Rakefile
|
86
|
+
- benchmarks/generate_parser_benchmarks
|
87
|
+
- benchmarks/parser.yml
|
85
88
|
- benchmarks/stringprep.yml
|
86
89
|
- benchmarks/table-regexps.yml
|
87
90
|
- docs/styles.css
|
88
91
|
- lib/net/imap.rb
|
89
92
|
- lib/net/imap/authenticators.rb
|
90
|
-
- lib/net/imap/authenticators/cram_md5.rb
|
91
|
-
- lib/net/imap/authenticators/digest_md5.rb
|
92
|
-
- lib/net/imap/authenticators/login.rb
|
93
|
-
- lib/net/imap/authenticators/plain.rb
|
94
|
-
- lib/net/imap/authenticators/xoauth2.rb
|
95
93
|
- lib/net/imap/command_data.rb
|
96
94
|
- lib/net/imap/data_encoding.rb
|
95
|
+
- lib/net/imap/deprecated_client_options.rb
|
97
96
|
- lib/net/imap/errors.rb
|
98
97
|
- lib/net/imap/flags.rb
|
99
98
|
- lib/net/imap/response_data.rb
|
100
99
|
- lib/net/imap/response_parser.rb
|
100
|
+
- lib/net/imap/response_parser/parser_utils.rb
|
101
101
|
- lib/net/imap/sasl.rb
|
102
|
-
- lib/net/imap/sasl/
|
103
|
-
- lib/net/imap/sasl/
|
102
|
+
- lib/net/imap/sasl/anonymous_authenticator.rb
|
103
|
+
- lib/net/imap/sasl/authentication_exchange.rb
|
104
|
+
- lib/net/imap/sasl/authenticators.rb
|
105
|
+
- lib/net/imap/sasl/client_adapter.rb
|
106
|
+
- lib/net/imap/sasl/cram_md5_authenticator.rb
|
107
|
+
- lib/net/imap/sasl/digest_md5_authenticator.rb
|
108
|
+
- lib/net/imap/sasl/external_authenticator.rb
|
109
|
+
- lib/net/imap/sasl/gs2_header.rb
|
110
|
+
- lib/net/imap/sasl/login_authenticator.rb
|
111
|
+
- lib/net/imap/sasl/oauthbearer_authenticator.rb
|
112
|
+
- lib/net/imap/sasl/plain_authenticator.rb
|
113
|
+
- lib/net/imap/sasl/protocol_adapters.rb
|
114
|
+
- lib/net/imap/sasl/scram_algorithm.rb
|
115
|
+
- lib/net/imap/sasl/scram_authenticator.rb
|
104
116
|
- lib/net/imap/sasl/stringprep.rb
|
105
|
-
- lib/net/imap/sasl/
|
117
|
+
- lib/net/imap/sasl/xoauth2_authenticator.rb
|
118
|
+
- lib/net/imap/sasl_adapter.rb
|
119
|
+
- lib/net/imap/stringprep.rb
|
120
|
+
- lib/net/imap/stringprep/nameprep.rb
|
121
|
+
- lib/net/imap/stringprep/saslprep.rb
|
122
|
+
- lib/net/imap/stringprep/saslprep_tables.rb
|
123
|
+
- lib/net/imap/stringprep/tables.rb
|
124
|
+
- lib/net/imap/stringprep/trace.rb
|
106
125
|
- net-imap.gemspec
|
107
126
|
- rakelib/rdoc.rake
|
108
127
|
- rakelib/rfcs.rake
|
@@ -123,14 +142,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
123
142
|
requirements:
|
124
143
|
- - ">="
|
125
144
|
- !ruby/object:Gem::Version
|
126
|
-
version: 2.
|
145
|
+
version: 2.7.3
|
127
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
147
|
requirements:
|
129
148
|
- - ">="
|
130
149
|
- !ruby/object:Gem::Version
|
131
150
|
version: '0'
|
132
151
|
requirements: []
|
133
|
-
rubygems_version: 3.4.
|
152
|
+
rubygems_version: 3.4.10
|
134
153
|
signing_key:
|
135
154
|
specification_version: 4
|
136
155
|
summary: Ruby client api for Internet Message Access Protocol
|
@@ -1,115 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Net::IMAP authenticator for the "`DIGEST-MD5`" SASL mechanism type, specified
|
4
|
-
# in RFC2831(https://tools.ietf.org/html/rfc2831). See Net::IMAP#authenticate.
|
5
|
-
#
|
6
|
-
# == Deprecated
|
7
|
-
#
|
8
|
-
# "+DIGEST-MD5+" has been deprecated by
|
9
|
-
# {RFC6331}[https://tools.ietf.org/html/rfc6331] and should not be relied on for
|
10
|
-
# security. It is included for compatibility with existing servers.
|
11
|
-
class Net::IMAP::DigestMD5Authenticator
|
12
|
-
def process(challenge)
|
13
|
-
case @stage
|
14
|
-
when STAGE_ONE
|
15
|
-
@stage = STAGE_TWO
|
16
|
-
sparams = {}
|
17
|
-
c = StringScanner.new(challenge)
|
18
|
-
while c.scan(/(?:\s*,)?\s*(\w+)=("(?:[^\\"]+|\\.)*"|[^,]+)\s*/)
|
19
|
-
k, v = c[1], c[2]
|
20
|
-
if v =~ /^"(.*)"$/
|
21
|
-
v = $1
|
22
|
-
if v =~ /,/
|
23
|
-
v = v.split(',')
|
24
|
-
end
|
25
|
-
end
|
26
|
-
sparams[k] = v
|
27
|
-
end
|
28
|
-
|
29
|
-
raise Net::IMAP::DataFormatError, "Bad Challenge: '#{challenge}'" unless c.eos?
|
30
|
-
raise Net::IMAP::Error, "Server does not support auth (qop = #{sparams['qop'].join(',')})" unless sparams['qop'].include?("auth")
|
31
|
-
|
32
|
-
response = {
|
33
|
-
:nonce => sparams['nonce'],
|
34
|
-
:username => @user,
|
35
|
-
:realm => sparams['realm'],
|
36
|
-
:cnonce => Digest::MD5.hexdigest("%.15f:%.15f:%d" % [Time.now.to_f, rand, Process.pid.to_s]),
|
37
|
-
:'digest-uri' => 'imap/' + sparams['realm'],
|
38
|
-
:qop => 'auth',
|
39
|
-
:maxbuf => 65535,
|
40
|
-
:nc => "%08d" % nc(sparams['nonce']),
|
41
|
-
:charset => sparams['charset'],
|
42
|
-
}
|
43
|
-
|
44
|
-
response[:authzid] = @authname unless @authname.nil?
|
45
|
-
|
46
|
-
# now, the real thing
|
47
|
-
a0 = Digest::MD5.digest( [ response.values_at(:username, :realm), @password ].join(':') )
|
48
|
-
|
49
|
-
a1 = [ a0, response.values_at(:nonce,:cnonce) ].join(':')
|
50
|
-
a1 << ':' + response[:authzid] unless response[:authzid].nil?
|
51
|
-
|
52
|
-
a2 = "AUTHENTICATE:" + response[:'digest-uri']
|
53
|
-
a2 << ":00000000000000000000000000000000" if response[:qop] and response[:qop] =~ /^auth-(?:conf|int)$/
|
54
|
-
|
55
|
-
response[:response] = Digest::MD5.hexdigest(
|
56
|
-
[
|
57
|
-
Digest::MD5.hexdigest(a1),
|
58
|
-
response.values_at(:nonce, :nc, :cnonce, :qop),
|
59
|
-
Digest::MD5.hexdigest(a2)
|
60
|
-
].join(':')
|
61
|
-
)
|
62
|
-
|
63
|
-
return response.keys.map {|key| qdval(key.to_s, response[key]) }.join(',')
|
64
|
-
when STAGE_TWO
|
65
|
-
@stage = nil
|
66
|
-
# if at the second stage, return an empty string
|
67
|
-
if challenge =~ /rspauth=/
|
68
|
-
return ''
|
69
|
-
else
|
70
|
-
raise ResponseParseError, challenge
|
71
|
-
end
|
72
|
-
else
|
73
|
-
raise ResponseParseError, challenge
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def initialize(user, password, authname = nil, warn_deprecation: true)
|
78
|
-
if warn_deprecation
|
79
|
-
warn "WARNING: DIGEST-MD5 SASL mechanism was deprecated by RFC6331."
|
80
|
-
# TODO: recommend SCRAM instead.
|
81
|
-
end
|
82
|
-
require "digest/md5"
|
83
|
-
require "strscan"
|
84
|
-
@user, @password, @authname = user, password, authname
|
85
|
-
@nc, @stage = {}, STAGE_ONE
|
86
|
-
end
|
87
|
-
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
STAGE_ONE = :stage_one
|
92
|
-
STAGE_TWO = :stage_two
|
93
|
-
|
94
|
-
def nc(nonce)
|
95
|
-
if @nc.has_key? nonce
|
96
|
-
@nc[nonce] = @nc[nonce] + 1
|
97
|
-
else
|
98
|
-
@nc[nonce] = 1
|
99
|
-
end
|
100
|
-
return @nc[nonce]
|
101
|
-
end
|
102
|
-
|
103
|
-
# some responses need quoting
|
104
|
-
def qdval(k, v)
|
105
|
-
return if k.nil? or v.nil?
|
106
|
-
if %w"username authzid realm nonce cnonce digest-uri qop".include? k
|
107
|
-
v = v.gsub(/([\\"])/, "\\\1")
|
108
|
-
return '%s="%s"' % [k, v]
|
109
|
-
else
|
110
|
-
return '%s=%s' % [k, v]
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
Net::IMAP.add_authenticator "DIGEST-MD5", self
|
115
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Authenticator for the "+PLAIN+" SASL mechanism, specified in
|
4
|
-
# RFC4616[https://tools.ietf.org/html/rfc4616]. See Net::IMAP#authenticate.
|
5
|
-
#
|
6
|
-
# +PLAIN+ authentication sends the password in cleartext.
|
7
|
-
# RFC3501[https://tools.ietf.org/html/rfc3501] encourages servers to disable
|
8
|
-
# cleartext authentication until after TLS has been negotiated.
|
9
|
-
# RFC8314[https://tools.ietf.org/html/rfc8314] recommends TLS version 1.2 or
|
10
|
-
# greater be used for all traffic, and deprecate cleartext access ASAP. +PLAIN+
|
11
|
-
# can be secured by TLS encryption.
|
12
|
-
class Net::IMAP::PlainAuthenticator
|
13
|
-
|
14
|
-
def process(data)
|
15
|
-
return "#@authzid\0#@username\0#@password"
|
16
|
-
end
|
17
|
-
|
18
|
-
# :nodoc:
|
19
|
-
NULL = -"\0".b
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
# +username+ is the authentication identity, the identity whose +password+ is
|
24
|
-
# used. +username+ is referred to as +authcid+ by
|
25
|
-
# RFC4616[https://tools.ietf.org/html/rfc4616].
|
26
|
-
#
|
27
|
-
# +authzid+ is the authorization identity (identity to act as). It can
|
28
|
-
# usually be left blank. When +authzid+ is left blank (nil or empty string)
|
29
|
-
# the server will derive an identity from the credentials and use that as the
|
30
|
-
# authorization identity.
|
31
|
-
def initialize(username, password, authzid: nil)
|
32
|
-
raise ArgumentError, "username contains NULL" if username&.include?(NULL)
|
33
|
-
raise ArgumentError, "password contains NULL" if password&.include?(NULL)
|
34
|
-
raise ArgumentError, "authzid contains NULL" if authzid&.include?(NULL)
|
35
|
-
@username = username
|
36
|
-
@password = password
|
37
|
-
@authzid = authzid
|
38
|
-
end
|
39
|
-
|
40
|
-
Net::IMAP.add_authenticator "PLAIN", self
|
41
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Net::IMAP::XOauth2Authenticator
|
4
|
-
def process(_data)
|
5
|
-
build_oauth2_string(@user, @oauth2_token)
|
6
|
-
end
|
7
|
-
|
8
|
-
private
|
9
|
-
|
10
|
-
def initialize(user, oauth2_token)
|
11
|
-
@user = user
|
12
|
-
@oauth2_token = oauth2_token
|
13
|
-
end
|
14
|
-
|
15
|
-
def build_oauth2_string(user, oauth2_token)
|
16
|
-
format("user=%s\1auth=Bearer %s\1\1", user, oauth2_token)
|
17
|
-
end
|
18
|
-
|
19
|
-
Net::IMAP.add_authenticator 'XOAUTH2', self
|
20
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "saslprep_tables"
|
4
|
-
|
5
|
-
module Net::IMAP::SASL
|
6
|
-
|
7
|
-
# SASLprep#saslprep can be used to prepare a string according to [RFC4013].
|
8
|
-
#
|
9
|
-
# \SASLprep maps characters three ways: to nothing, to space, and Unicode
|
10
|
-
# normalization form KC. \SASLprep prohibits codepoints from nearly all
|
11
|
-
# standard StringPrep tables (RFC3454, Appendix "C"), and uses \StringPrep's
|
12
|
-
# standard bidirectional characters requirements (Appendix "D"). \SASLprep
|
13
|
-
# also uses \StringPrep's definition of "Unassigned" codepoints (Appendix "A").
|
14
|
-
module SASLprep
|
15
|
-
|
16
|
-
# Used to short-circuit strings that don't need preparation.
|
17
|
-
ASCII_NO_CTRLS = /\A[\x20-\x7e]*\z/u.freeze
|
18
|
-
|
19
|
-
module_function
|
20
|
-
|
21
|
-
# Prepares a UTF-8 +string+ for comparison, using the \SASLprep profile
|
22
|
-
# RFC4013 of the StringPrep algorithm RFC3454.
|
23
|
-
#
|
24
|
-
# By default, prohibited strings will return +nil+. When +exception+ is
|
25
|
-
# +true+, a StringPrepError describing the violation will be raised.
|
26
|
-
#
|
27
|
-
# When +stored+ is +true+, "unassigned" codepoints will be prohibited. For
|
28
|
-
# \StringPrep and the \SASLprep profile, "unassigned" refers to Unicode 3.2,
|
29
|
-
# and not later versions. See RFC3454 §7 for more information.
|
30
|
-
#
|
31
|
-
def saslprep(str, stored: false, exception: false)
|
32
|
-
return str if ASCII_NO_CTRLS.match?(str) # raises on incompatible encoding
|
33
|
-
str = str.encode("UTF-8") # also dups (and raises for invalid encoding)
|
34
|
-
str.gsub!(MAP_TO_SPACE, " ")
|
35
|
-
str.gsub!(MAP_TO_NOTHING, "")
|
36
|
-
str.unicode_normalize!(:nfkc)
|
37
|
-
# These regexps combine the prohibited and bidirectional checks
|
38
|
-
return str unless str.match?(stored ? PROHIBITED_STORED : PROHIBITED)
|
39
|
-
return nil unless exception
|
40
|
-
# raise helpful errors to indicate *why* it failed:
|
41
|
-
tables = stored ? TABLES_PROHIBITED_STORED : TABLES_PROHIBITED
|
42
|
-
StringPrep.check_prohibited! str, *tables, bidi: true, profile: "SASLprep"
|
43
|
-
raise StringPrep::InvalidStringError.new(
|
44
|
-
"unknown error", string: string, profile: "SASLprep"
|
45
|
-
)
|
46
|
-
rescue ArgumentError, Encoding::CompatibilityError => ex
|
47
|
-
if /invalid byte sequence|incompatible encoding/.match? ex.message
|
48
|
-
return nil unless exception
|
49
|
-
raise StringPrepError.new(ex.message, string: str, profile: "saslprep")
|
50
|
-
end
|
51
|
-
raise ex
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|