net-imap 0.3.7 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/pages.yml +46 -0
- data/.github/workflows/test.yml +5 -12
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/README.md +15 -4
- data/Rakefile +0 -7
- data/docs/styles.css +0 -12
- data/lib/net/imap/authenticators.rb +26 -57
- data/lib/net/imap/command_data.rb +13 -6
- data/lib/net/imap/data_encoding.rb +14 -2
- data/lib/net/imap/deprecated_client_options.rb +139 -0
- data/lib/net/imap/errors.rb +20 -0
- data/lib/net/imap/fetch_data.rb +518 -0
- data/lib/net/imap/response_data.rb +116 -252
- data/lib/net/imap/response_parser/parser_utils.rb +240 -0
- data/lib/net/imap/response_parser.rb +1535 -1003
- data/lib/net/imap/sasl/anonymous_authenticator.rb +69 -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} +21 -11
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +180 -0
- data/lib/net/imap/sasl/external_authenticator.rb +83 -0
- data/lib/net/imap/sasl/gs2_header.rb +80 -0
- data/lib/net/imap/{authenticators/login.rb → sasl/login_authenticator.rb} +25 -16
- data/lib/net/imap/sasl/oauthbearer_authenticator.rb +199 -0
- data/lib/net/imap/sasl/plain_authenticator.rb +101 -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 +287 -0
- data/lib/net/imap/sasl/stringprep.rb +6 -66
- data/lib/net/imap/sasl/xoauth2_authenticator.rb +106 -0
- data/lib/net/imap/sasl.rb +144 -43
- data/lib/net/imap/sasl_adapter.rb +21 -0
- data/lib/net/imap/sequence_set.rb +67 -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 +1055 -612
- data/net-imap.gemspec +4 -3
- data/rakelib/benchmarks.rake +91 -0
- data/rakelib/saslprep.rake +4 -4
- data/rakelib/string_prep_tables_generator.rb +82 -60
- metadata +31 -13
- data/benchmarks/stringprep.yml +0 -65
- data/benchmarks/table-regexps.yml +0 -39
- 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
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
name = File.basename(__FILE__, ".gemspec")
|
4
4
|
version = ["lib", Array.new(name.count("-"), "..").join("/")].find do |dir|
|
5
|
-
break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
|
5
|
+
break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb"), :encoding=> 'utf-8') do |line|
|
6
6
|
/^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
|
7
7
|
end rescue nil
|
8
8
|
end
|
@@ -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,8 @@ 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")
|
28
|
+
`git ls-files -z 2>/dev/null`.split("\x0")
|
29
|
+
.reject {|f| f.match(%r{^(bin|test|spec|benchmarks|features|rfcs)/}) }
|
29
30
|
end
|
30
31
|
spec.bindir = "exe"
|
31
32
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
PARSER_TEST_FIXTURES = FileList.new "test/net/imap/fixtures/response_parser/*.yml"
|
4
|
+
CLOBBER.include "benchmarks/parser.yml"
|
5
|
+
CLEAN.include "benchmarks/Gemfile-*"
|
6
|
+
|
7
|
+
BENCHMARK_INIT = <<RUBY
|
8
|
+
require "yaml"
|
9
|
+
require "net/imap"
|
10
|
+
|
11
|
+
def load_response(file, name)
|
12
|
+
YAML.unsafe_load_file(file).dig(:tests, name, :response)
|
13
|
+
.force_encoding "ASCII-8BIT" \\
|
14
|
+
or abort "ERRORO: missing %p fixture data in %p" % [name, file]
|
15
|
+
end
|
16
|
+
|
17
|
+
parser = Net::IMAP::ResponseParser.new
|
18
|
+
RUBY
|
19
|
+
|
20
|
+
file "benchmarks/parser.yml" => PARSER_TEST_FIXTURES do |t|
|
21
|
+
require "yaml"
|
22
|
+
require "pathname"
|
23
|
+
require "net/imap"
|
24
|
+
|
25
|
+
path = Pathname.new(__dir__) / "../test/net/imap/fixtures/response_parser"
|
26
|
+
files = path.glob("*.yml")
|
27
|
+
tests = files.flat_map {|file|
|
28
|
+
file.read
|
29
|
+
.gsub(%r{([-:]) !ruby/(object|struct):\S+}) { $1 }
|
30
|
+
.then {
|
31
|
+
YAML.safe_load(_1, filename: file,
|
32
|
+
permitted_classes: [Symbol, Regexp], aliases: true)
|
33
|
+
}
|
34
|
+
.fetch(:tests)
|
35
|
+
.select {|test_name, test|
|
36
|
+
:parser_assert_equal == test.fetch(:test_type) {
|
37
|
+
test.key?(:expected) ? :parser_assert_equal : :parser_pending
|
38
|
+
}
|
39
|
+
}
|
40
|
+
.map {|test_name, test| [test_name.to_s, test.fetch(:response)] }
|
41
|
+
}
|
42
|
+
|
43
|
+
benchmarks = tests.map {|fixture_name, response|
|
44
|
+
{"name" => fixture_name.delete_prefix("test_"),
|
45
|
+
"prelude" => "response = %s" % [response.dump],
|
46
|
+
"script" => "parser.parse(response)"}
|
47
|
+
}
|
48
|
+
.sort_by { _1["name"] }
|
49
|
+
|
50
|
+
YAML.dump({"prelude" => BENCHMARK_INIT, "benchmark" => benchmarks})
|
51
|
+
.then { File.write t.name, _1 }
|
52
|
+
end
|
53
|
+
|
54
|
+
namespace :benchmarks do
|
55
|
+
desc "Generate benchmarks from fixture data"
|
56
|
+
task :generate => "benchmarks/parser.yml"
|
57
|
+
|
58
|
+
desc "run the parser benchmarks comparing multiple gem versions"
|
59
|
+
task :compare => :generate do |task, args|
|
60
|
+
cd Pathname.new(__dir__) + ".."
|
61
|
+
current = `git describe --tags --dirty`.chomp
|
62
|
+
current = "dev" if current.empty?
|
63
|
+
versions = args.to_a
|
64
|
+
if versions.empty?
|
65
|
+
latest = %x{git describe --tags --abbrev=0 --match 'v*.*.*'}.chomp
|
66
|
+
versions = latest.empty? ? [] : [latest.delete_prefix("v")]
|
67
|
+
end
|
68
|
+
versions = versions.to_h { [_1, "Gemfile-v#{_1}"] }
|
69
|
+
cd "benchmarks" do
|
70
|
+
versions.each do |version, gemfile|
|
71
|
+
File.write gemfile, <<~RUBY
|
72
|
+
# frozen_string_literal: true
|
73
|
+
source "https://rubygems.org"
|
74
|
+
gem "net-imap", #{version.dump}
|
75
|
+
RUBY
|
76
|
+
end
|
77
|
+
versions = {current => "../Gemfile" , **versions}.map {
|
78
|
+
"%s::/usr/bin/env BUNDLE_GEMFILE=%s ruby" % _1
|
79
|
+
}.join(";")
|
80
|
+
|
81
|
+
extra = ENV.fetch("BENCHMARK_ARGS", "").shellsplit
|
82
|
+
|
83
|
+
sh("benchmark-driver",
|
84
|
+
"--bundler",
|
85
|
+
"-e", versions,
|
86
|
+
"parser.yml",
|
87
|
+
*extra)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
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.5
|
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: 2023-
|
12
|
+
date: 2023-11-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: net-protocol
|
@@ -76,34 +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
|
85
|
-
- benchmarks/stringprep.yml
|
86
|
-
- benchmarks/table-regexps.yml
|
87
86
|
- docs/styles.css
|
88
87
|
- lib/net/imap.rb
|
89
88
|
- 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
89
|
- lib/net/imap/command_data.rb
|
96
90
|
- lib/net/imap/data_encoding.rb
|
91
|
+
- lib/net/imap/deprecated_client_options.rb
|
97
92
|
- lib/net/imap/errors.rb
|
93
|
+
- lib/net/imap/fetch_data.rb
|
98
94
|
- lib/net/imap/flags.rb
|
99
95
|
- lib/net/imap/response_data.rb
|
100
96
|
- lib/net/imap/response_parser.rb
|
97
|
+
- lib/net/imap/response_parser/parser_utils.rb
|
101
98
|
- lib/net/imap/sasl.rb
|
102
|
-
- lib/net/imap/sasl/
|
103
|
-
- lib/net/imap/sasl/
|
99
|
+
- lib/net/imap/sasl/anonymous_authenticator.rb
|
100
|
+
- lib/net/imap/sasl/authentication_exchange.rb
|
101
|
+
- lib/net/imap/sasl/authenticators.rb
|
102
|
+
- lib/net/imap/sasl/client_adapter.rb
|
103
|
+
- lib/net/imap/sasl/cram_md5_authenticator.rb
|
104
|
+
- lib/net/imap/sasl/digest_md5_authenticator.rb
|
105
|
+
- lib/net/imap/sasl/external_authenticator.rb
|
106
|
+
- lib/net/imap/sasl/gs2_header.rb
|
107
|
+
- lib/net/imap/sasl/login_authenticator.rb
|
108
|
+
- lib/net/imap/sasl/oauthbearer_authenticator.rb
|
109
|
+
- lib/net/imap/sasl/plain_authenticator.rb
|
110
|
+
- lib/net/imap/sasl/protocol_adapters.rb
|
111
|
+
- lib/net/imap/sasl/scram_algorithm.rb
|
112
|
+
- lib/net/imap/sasl/scram_authenticator.rb
|
104
113
|
- lib/net/imap/sasl/stringprep.rb
|
105
|
-
- lib/net/imap/sasl/
|
114
|
+
- lib/net/imap/sasl/xoauth2_authenticator.rb
|
115
|
+
- lib/net/imap/sasl_adapter.rb
|
116
|
+
- lib/net/imap/sequence_set.rb
|
117
|
+
- lib/net/imap/stringprep.rb
|
118
|
+
- lib/net/imap/stringprep/nameprep.rb
|
119
|
+
- lib/net/imap/stringprep/saslprep.rb
|
120
|
+
- lib/net/imap/stringprep/saslprep_tables.rb
|
121
|
+
- lib/net/imap/stringprep/tables.rb
|
122
|
+
- lib/net/imap/stringprep/trace.rb
|
106
123
|
- net-imap.gemspec
|
124
|
+
- rakelib/benchmarks.rake
|
107
125
|
- rakelib/rdoc.rake
|
108
126
|
- rakelib/rfcs.rake
|
109
127
|
- rakelib/saslprep.rake
|
@@ -123,7 +141,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
123
141
|
requirements:
|
124
142
|
- - ">="
|
125
143
|
- !ruby/object:Gem::Version
|
126
|
-
version: 2.
|
144
|
+
version: 2.7.3
|
127
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
146
|
requirements:
|
129
147
|
- - ">="
|
data/benchmarks/stringprep.yml
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
---
|
2
|
-
prelude: |
|
3
|
-
begin
|
4
|
-
require "mongo" # gem install mongo
|
5
|
-
require "idn" # gem install idn-ruby
|
6
|
-
rescue LoadError
|
7
|
-
warn "You must 'gem install mongo idn-ruby' for this benchmark."
|
8
|
-
raise
|
9
|
-
end
|
10
|
-
|
11
|
-
MStrPrep = Mongo::Auth::StringPrep
|
12
|
-
|
13
|
-
# this indirection will slow it down a little bit
|
14
|
-
def mongo_saslprep(string)
|
15
|
-
MStrPrep.prepare(string,
|
16
|
-
MStrPrep::Profiles::SASL::MAPPINGS,
|
17
|
-
MStrPrep::Profiles::SASL::PROHIBITED,
|
18
|
-
normalize: true,
|
19
|
-
bidi: true)
|
20
|
-
rescue Mongo::Error::FailedStringPrepValidation
|
21
|
-
nil
|
22
|
-
end
|
23
|
-
|
24
|
-
$LOAD_PATH.unshift "./lib"
|
25
|
-
require "net/imap"
|
26
|
-
def net_imap_saslprep(string)
|
27
|
-
Net::IMAP::SASL::SASLprep.saslprep string, exception: false
|
28
|
-
end
|
29
|
-
|
30
|
-
def libidn_saslprep(string)
|
31
|
-
IDN::Stringprep.with_profile(string, "SASLprep")
|
32
|
-
rescue IDN::Stringprep::StringprepError
|
33
|
-
nil
|
34
|
-
end
|
35
|
-
|
36
|
-
benchmark:
|
37
|
-
- net_imap_saslprep "I\u00ADX" # RFC example 1. IX
|
38
|
-
- net_imap_saslprep "user" # RFC example 2. user
|
39
|
-
- net_imap_saslprep "USER" # RFC example 3. user
|
40
|
-
- net_imap_saslprep "\u00aa" # RFC example 4. a
|
41
|
-
- net_imap_saslprep "\u2168" # RFC example 5. IX
|
42
|
-
- net_imap_saslprep "\u0007" # RFC example 6. Error - prohibited character
|
43
|
-
- net_imap_saslprep "\u0627\u0031" # RFC example 7. Error - bidirectional check
|
44
|
-
- net_imap_saslprep "I\u2000X" # map to space: I X
|
45
|
-
- net_imap_saslprep "a longer string, e.g. a password"
|
46
|
-
|
47
|
-
- libidn_saslprep "I\u00ADX" # RFC example 1. IX
|
48
|
-
- libidn_saslprep "user" # RFC example 2. user
|
49
|
-
- libidn_saslprep "USER" # RFC example 3. user
|
50
|
-
- libidn_saslprep "\u00aa" # RFC example 4. a
|
51
|
-
- libidn_saslprep "\u2168" # RFC example 5. IX
|
52
|
-
- libidn_saslprep "\u0007" # RFC example 6. Error - prohibited character
|
53
|
-
- libidn_saslprep "\u0627\u0031" # RFC example 7. Error - bidirectional check
|
54
|
-
- libidn_saslprep "I\u2000X" # map to space: I X
|
55
|
-
- libidn_saslprep "a longer string, e.g. a password"
|
56
|
-
|
57
|
-
- mongo_saslprep "I\u00ADX" # RFC example 1. IX
|
58
|
-
- mongo_saslprep "user" # RFC example 2. user
|
59
|
-
- mongo_saslprep "USER" # RFC example 3. user
|
60
|
-
- mongo_saslprep "\u00aa" # RFC example 4. a
|
61
|
-
- mongo_saslprep "\u2168" # RFC example 5. IX
|
62
|
-
- mongo_saslprep "\u0007" # RFC example 6. Error - prohibited character
|
63
|
-
- mongo_saslprep "\u0627\u0031" # RFC example 7. Error - bidirectional check
|
64
|
-
- mongo_saslprep "I\u2000X" # map to space: I X
|
65
|
-
- mongo_saslprep "a longer string, e.g. a password"
|
@@ -1,39 +0,0 @@
|
|
1
|
-
prelude: |
|
2
|
-
require "json"
|
3
|
-
require "set"
|
4
|
-
|
5
|
-
all_codepoints = (0..0x10ffff).map{_1.chr("UTF-8") rescue nil}.compact
|
6
|
-
|
7
|
-
rfc3454_tables = Dir["rfcs/rfc3454*.json"]
|
8
|
-
.first
|
9
|
-
.then{File.read _1}
|
10
|
-
.then{JSON.parse _1}
|
11
|
-
titles = rfc3454_tables.delete("titles")
|
12
|
-
|
13
|
-
sets = rfc3454_tables
|
14
|
-
.transform_values{|t|t.keys rescue t}
|
15
|
-
.transform_values{|table|
|
16
|
-
table
|
17
|
-
.map{_1.split(?-).map{|i|Integer i, 16}}
|
18
|
-
.flat_map{_2 ? (_1.._2).to_a : _1}
|
19
|
-
.to_set
|
20
|
-
}
|
21
|
-
|
22
|
-
TABLE_A1_SET = sets.fetch "A.1"
|
23
|
-
ASSIGNED_3_2 = /\p{AGE=3.2}/
|
24
|
-
UNASSIGNED_3_2 = /\P{AGE=3.2}/
|
25
|
-
TABLE_A1_REGEX = /(?-mix:[\u{0000}-\u{001f}\u{007f}-\u{00a0}\u{0340}-\u{0341}\u{06dd}\u{070f}\u{1680}\u{180e}\u{2000}-\u{200f}\u{2028}-\u{202f}\u{205f}-\u{2063}\u{206a}-\u{206f}\u{2ff0}-\u{2ffb}\u{3000}\u{e000}-\u{f8ff}\u{fdd0}-\u{fdef}\u{feff}\u{fff9}-\u{ffff}\u{1d173}-\u{1d17a}\u{1fffe}-\u{1ffff}\u{2fffe}-\u{2ffff}\u{3fffe}-\u{3ffff}\u{4fffe}-\u{4ffff}\u{5fffe}-\u{5ffff}\u{6fffe}-\u{6ffff}\u{7fffe}-\u{7ffff}\u{8fffe}-\u{8ffff}\u{9fffe}-\u{9ffff}\u{afffe}-\u{affff}\u{bfffe}-\u{bffff}\u{cfffe}-\u{cffff}\u{dfffe}-\u{dffff}\u{e0001}\u{e0020}-\u{e007f}\u{efffe}-\u{10ffff}])|(?-mix:\p{Cs})/.freeze
|
26
|
-
|
27
|
-
benchmark:
|
28
|
-
|
29
|
-
# matches A.1
|
30
|
-
- script: "all_codepoints.grep(TABLE_A1_SET)"
|
31
|
-
- script: "all_codepoints.grep(TABLE_A1_REGEX)"
|
32
|
-
- script: "all_codepoints.grep(UNASSIGNED_3_2)"
|
33
|
-
- script: "all_codepoints.grep_v(ASSIGNED_3_2)"
|
34
|
-
|
35
|
-
# doesn't match A.1
|
36
|
-
- script: "all_codepoints.grep_v(TABLE_A1_SET)"
|
37
|
-
- script: "all_codepoints.grep_v(TABLE_A1_REGEX)"
|
38
|
-
- script: "all_codepoints.grep_v(UNASSIGNED_3_2)"
|
39
|
-
- script: "all_codepoints.grep(ASSIGNED_3_2)"
|