net-imap 0.3.9 → 0.5.6
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/BSDL +22 -0
- data/COPYING +56 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +3 -22
- data/README.md +25 -8
- data/Rakefile +0 -7
- data/docs/styles.css +72 -23
- data/lib/net/imap/authenticators.rb +26 -57
- data/lib/net/imap/command_data.rb +74 -54
- data/lib/net/imap/config/attr_accessors.rb +75 -0
- data/lib/net/imap/config/attr_inheritance.rb +90 -0
- data/lib/net/imap/config/attr_type_coercion.rb +61 -0
- data/lib/net/imap/config.rb +470 -0
- data/lib/net/imap/data_encoding.rb +18 -6
- data/lib/net/imap/data_lite.rb +226 -0
- data/lib/net/imap/deprecated_client_options.rb +142 -0
- data/lib/net/imap/errors.rb +27 -35
- data/lib/net/imap/esearch_result.rb +180 -0
- data/lib/net/imap/fetch_data.rb +597 -0
- data/lib/net/imap/flags.rb +1 -1
- data/lib/net/imap/response_data.rb +250 -440
- data/lib/net/imap/response_parser/parser_utils.rb +245 -0
- data/lib/net/imap/response_parser.rb +1873 -1210
- data/lib/net/imap/sasl/anonymous_authenticator.rb +69 -0
- data/lib/net/imap/sasl/authentication_exchange.rb +139 -0
- data/lib/net/imap/sasl/authenticators.rb +122 -0
- data/lib/net/imap/sasl/client_adapter.rb +123 -0
- data/lib/net/imap/{authenticators/cram_md5.rb → sasl/cram_md5_authenticator.rb} +24 -14
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +342 -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} +28 -18
- 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 +101 -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 +148 -44
- data/lib/net/imap/sasl_adapter.rb +20 -0
- data/lib/net/imap/search_result.rb +146 -0
- data/lib/net/imap/sequence_set.rb +1565 -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/uidplus_data.rb +244 -0
- data/lib/net/imap/vanished_data.rb +56 -0
- data/lib/net/imap.rb +2109 -924
- data/net-imap.gemspec +7 -8
- data/rakelib/benchmarks.rake +91 -0
- data/rakelib/rfcs.rake +2 -0
- data/rakelib/saslprep.rake +4 -4
- data/rakelib/string_prep_tables_generator.rb +84 -60
- data/sample/net-imap.rb +167 -0
- metadata +45 -47
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/test.yml +0 -38
- data/.gitignore +0 -10
- 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/response_reader.rb +0 -75
- 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
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-imap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
8
|
- nicholas a. evans
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-02-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-protocol
|
@@ -38,76 +38,73 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: digest
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: strscan
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
41
|
description: Ruby client api for Internet Message Access Protocol
|
70
42
|
email:
|
71
43
|
- shugo@ruby-lang.org
|
72
|
-
- nick@
|
44
|
+
- nick@rubinick.dev
|
73
45
|
executables: []
|
74
46
|
extensions: []
|
75
47
|
extra_rdoc_files: []
|
76
48
|
files:
|
77
|
-
-
|
78
|
-
-
|
79
|
-
- ".gitignore"
|
49
|
+
- BSDL
|
50
|
+
- COPYING
|
80
51
|
- Gemfile
|
81
52
|
- LICENSE.txt
|
82
53
|
- README.md
|
83
54
|
- Rakefile
|
84
|
-
- benchmarks/stringprep.yml
|
85
|
-
- benchmarks/table-regexps.yml
|
86
55
|
- docs/styles.css
|
87
56
|
- lib/net/imap.rb
|
88
57
|
- lib/net/imap/authenticators.rb
|
89
|
-
- lib/net/imap/authenticators/cram_md5.rb
|
90
|
-
- lib/net/imap/authenticators/digest_md5.rb
|
91
|
-
- lib/net/imap/authenticators/login.rb
|
92
|
-
- lib/net/imap/authenticators/plain.rb
|
93
|
-
- lib/net/imap/authenticators/xoauth2.rb
|
94
58
|
- lib/net/imap/command_data.rb
|
59
|
+
- lib/net/imap/config.rb
|
60
|
+
- lib/net/imap/config/attr_accessors.rb
|
61
|
+
- lib/net/imap/config/attr_inheritance.rb
|
62
|
+
- lib/net/imap/config/attr_type_coercion.rb
|
95
63
|
- lib/net/imap/data_encoding.rb
|
64
|
+
- lib/net/imap/data_lite.rb
|
65
|
+
- lib/net/imap/deprecated_client_options.rb
|
96
66
|
- lib/net/imap/errors.rb
|
67
|
+
- lib/net/imap/esearch_result.rb
|
68
|
+
- lib/net/imap/fetch_data.rb
|
97
69
|
- lib/net/imap/flags.rb
|
98
70
|
- lib/net/imap/response_data.rb
|
99
71
|
- lib/net/imap/response_parser.rb
|
100
|
-
- lib/net/imap/
|
72
|
+
- lib/net/imap/response_parser/parser_utils.rb
|
101
73
|
- lib/net/imap/sasl.rb
|
102
|
-
- lib/net/imap/sasl/
|
103
|
-
- lib/net/imap/sasl/
|
74
|
+
- lib/net/imap/sasl/anonymous_authenticator.rb
|
75
|
+
- lib/net/imap/sasl/authentication_exchange.rb
|
76
|
+
- lib/net/imap/sasl/authenticators.rb
|
77
|
+
- lib/net/imap/sasl/client_adapter.rb
|
78
|
+
- lib/net/imap/sasl/cram_md5_authenticator.rb
|
79
|
+
- lib/net/imap/sasl/digest_md5_authenticator.rb
|
80
|
+
- lib/net/imap/sasl/external_authenticator.rb
|
81
|
+
- lib/net/imap/sasl/gs2_header.rb
|
82
|
+
- lib/net/imap/sasl/login_authenticator.rb
|
83
|
+
- lib/net/imap/sasl/oauthbearer_authenticator.rb
|
84
|
+
- lib/net/imap/sasl/plain_authenticator.rb
|
85
|
+
- lib/net/imap/sasl/protocol_adapters.rb
|
86
|
+
- lib/net/imap/sasl/scram_algorithm.rb
|
87
|
+
- lib/net/imap/sasl/scram_authenticator.rb
|
104
88
|
- lib/net/imap/sasl/stringprep.rb
|
105
|
-
- lib/net/imap/sasl/
|
89
|
+
- lib/net/imap/sasl/xoauth2_authenticator.rb
|
90
|
+
- lib/net/imap/sasl_adapter.rb
|
91
|
+
- lib/net/imap/search_result.rb
|
92
|
+
- lib/net/imap/sequence_set.rb
|
93
|
+
- lib/net/imap/stringprep.rb
|
94
|
+
- lib/net/imap/stringprep/nameprep.rb
|
95
|
+
- lib/net/imap/stringprep/saslprep.rb
|
96
|
+
- lib/net/imap/stringprep/saslprep_tables.rb
|
97
|
+
- lib/net/imap/stringprep/tables.rb
|
98
|
+
- lib/net/imap/stringprep/trace.rb
|
99
|
+
- lib/net/imap/uidplus_data.rb
|
100
|
+
- lib/net/imap/vanished_data.rb
|
106
101
|
- net-imap.gemspec
|
102
|
+
- rakelib/benchmarks.rake
|
107
103
|
- rakelib/rdoc.rake
|
108
104
|
- rakelib/rfcs.rake
|
109
105
|
- rakelib/saslprep.rake
|
110
106
|
- rakelib/string_prep_tables_generator.rb
|
107
|
+
- sample/net-imap.rb
|
111
108
|
homepage: https://github.com/ruby/net-imap
|
112
109
|
licenses:
|
113
110
|
- Ruby
|
@@ -115,6 +112,7 @@ licenses:
|
|
115
112
|
metadata:
|
116
113
|
homepage_uri: https://github.com/ruby/net-imap
|
117
114
|
source_code_uri: https://github.com/ruby/net-imap
|
115
|
+
changelog_uri: https://github.com/ruby/net-imap/releases
|
118
116
|
rdoc_options: []
|
119
117
|
require_paths:
|
120
118
|
- lib
|
@@ -122,14 +120,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
120
|
requirements:
|
123
121
|
- - ">="
|
124
122
|
- !ruby/object:Gem::Version
|
125
|
-
version:
|
123
|
+
version: 3.1.0
|
126
124
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
125
|
requirements:
|
128
126
|
- - ">="
|
129
127
|
- !ruby/object:Gem::Version
|
130
128
|
version: '0'
|
131
129
|
requirements: []
|
132
|
-
rubygems_version: 3.6.
|
130
|
+
rubygems_version: 3.6.2
|
133
131
|
specification_version: 4
|
134
132
|
summary: Ruby client api for Internet Message Access Protocol
|
135
133
|
test_files: []
|
data/.github/dependabot.yml
DELETED
data/.github/workflows/test.yml
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
name: ubuntu
|
2
|
-
|
3
|
-
on: [push, pull_request]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
ruby-versions:
|
7
|
-
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
|
8
|
-
with:
|
9
|
-
engine: cruby
|
10
|
-
min_version: 2.6
|
11
|
-
|
12
|
-
build:
|
13
|
-
needs: ruby-versions
|
14
|
-
name: build (${{ matrix.ruby }} / ${{ matrix.os }})
|
15
|
-
strategy:
|
16
|
-
matrix:
|
17
|
-
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
|
18
|
-
os: [ ubuntu-latest, macos-latest ]
|
19
|
-
experimental: [false]
|
20
|
-
include:
|
21
|
-
# - ruby: 2.6
|
22
|
-
# os: ubuntu-latest
|
23
|
-
# experimental: true
|
24
|
-
- ruby: 2.6
|
25
|
-
os: macos-latest
|
26
|
-
experimental: false
|
27
|
-
runs-on: ${{ matrix.os }}
|
28
|
-
continue-on-error: ${{ matrix.experimental }}
|
29
|
-
steps:
|
30
|
-
- uses: actions/checkout@v3
|
31
|
-
- name: Set up Ruby
|
32
|
-
uses: ruby/setup-ruby@v1
|
33
|
-
with:
|
34
|
-
ruby-version: ${{ matrix.ruby }}
|
35
|
-
- name: Install dependencies
|
36
|
-
run: bundle install
|
37
|
-
- name: Run test
|
38
|
-
run: rake test
|
data/.gitignore
DELETED
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)"
|
@@ -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? and sparams['qop']
|
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,75 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Net
|
4
|
-
class IMAP
|
5
|
-
# See https://www.rfc-editor.org/rfc/rfc9051#section-2.2.2
|
6
|
-
class ResponseReader # :nodoc:
|
7
|
-
attr_reader :client
|
8
|
-
|
9
|
-
def initialize(client, sock)
|
10
|
-
@client, @sock = client, sock
|
11
|
-
end
|
12
|
-
|
13
|
-
def read_response_buffer
|
14
|
-
@buff = String.new
|
15
|
-
catch :eof do
|
16
|
-
while true
|
17
|
-
read_line
|
18
|
-
break unless (@literal_size = get_literal_size)
|
19
|
-
read_literal
|
20
|
-
end
|
21
|
-
end
|
22
|
-
buff
|
23
|
-
ensure
|
24
|
-
@buff = nil
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
attr_reader :buff, :literal_size
|
30
|
-
|
31
|
-
def bytes_read; buff.bytesize end
|
32
|
-
def empty?; buff.empty? end
|
33
|
-
def done?; line_done? && !get_literal_size end
|
34
|
-
def line_done?; buff.end_with?(CRLF) end
|
35
|
-
def get_literal_size; /\{(\d+)\}\r\n\z/n =~ buff && $1.to_i end
|
36
|
-
|
37
|
-
def read_line
|
38
|
-
buff << (@sock.gets(CRLF, read_limit) or throw :eof)
|
39
|
-
max_response_remaining! unless line_done?
|
40
|
-
end
|
41
|
-
|
42
|
-
def read_literal
|
43
|
-
# check before allocating memory for literal
|
44
|
-
max_response_remaining!
|
45
|
-
literal = String.new(capacity: literal_size)
|
46
|
-
buff << (@sock.read(read_limit(literal_size), literal) or throw :eof)
|
47
|
-
ensure
|
48
|
-
@literal_size = nil
|
49
|
-
end
|
50
|
-
|
51
|
-
def read_limit(limit = nil)
|
52
|
-
[limit, max_response_remaining!].compact.min
|
53
|
-
end
|
54
|
-
|
55
|
-
def max_response_size; client.max_response_size end
|
56
|
-
def max_response_remaining; max_response_size &.- bytes_read end
|
57
|
-
def response_too_large?; max_response_size &.< min_response_size end
|
58
|
-
def min_response_size; bytes_read + min_response_remaining end
|
59
|
-
|
60
|
-
def min_response_remaining
|
61
|
-
empty? ? 3 : done? ? 0 : (literal_size || 0) + 2
|
62
|
-
end
|
63
|
-
|
64
|
-
def max_response_remaining!
|
65
|
-
return max_response_remaining unless response_too_large?
|
66
|
-
raise ResponseTooLargeError.new(
|
67
|
-
max_response_size: max_response_size,
|
68
|
-
bytes_read: bytes_read,
|
69
|
-
literal_size: literal_size,
|
70
|
-
)
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
end
|
75
|
-
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
|