net-imap 0.5.1 → 0.5.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +10 -4
- data/docs/styles.css +75 -14
- data/lib/net/imap/command_data.rb +48 -46
- data/lib/net/imap/config.rb +73 -3
- data/lib/net/imap/data_lite.rb +226 -0
- data/lib/net/imap/esearch_result.rb +180 -0
- data/lib/net/imap/fetch_data.rb +126 -47
- data/lib/net/imap/response_data.rb +118 -144
- data/lib/net/imap/response_parser/parser_utils.rb +5 -0
- data/lib/net/imap/response_parser.rb +178 -17
- data/lib/net/imap/sasl/anonymous_authenticator.rb +3 -3
- data/lib/net/imap/sasl/cram_md5_authenticator.rb +3 -3
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +8 -8
- data/lib/net/imap/sasl/external_authenticator.rb +2 -2
- data/lib/net/imap/sasl/gs2_header.rb +7 -7
- data/lib/net/imap/sasl/login_authenticator.rb +2 -2
- data/lib/net/imap/sasl/oauthbearer_authenticator.rb +6 -6
- data/lib/net/imap/sasl/plain_authenticator.rb +7 -7
- data/lib/net/imap/sasl/scram_authenticator.rb +8 -8
- data/lib/net/imap/sasl.rb +1 -1
- data/lib/net/imap/search_result.rb +2 -2
- data/lib/net/imap/sequence_set.rb +193 -58
- data/lib/net/imap/stringprep/nameprep.rb +1 -1
- data/lib/net/imap/stringprep/trace.rb +4 -4
- data/lib/net/imap/uidplus_data.rb +244 -0
- data/lib/net/imap/vanished_data.rb +56 -0
- data/lib/net/imap.rb +694 -319
- data/rakelib/rfcs.rake +2 -0
- metadata +7 -6
@@ -13,13 +13,17 @@ module Net
|
|
13
13
|
|
14
14
|
attr_reader :config
|
15
15
|
|
16
|
-
#
|
16
|
+
# Creates a new ResponseParser.
|
17
|
+
#
|
18
|
+
# When +config+ is frozen or global, the parser #config inherits from it.
|
19
|
+
# Otherwise, +config+ will be used directly.
|
17
20
|
def initialize(config: Config.global)
|
18
21
|
@str = nil
|
19
22
|
@pos = nil
|
20
23
|
@lex_state = nil
|
21
24
|
@token = nil
|
22
25
|
@config = Config[config]
|
26
|
+
@config = @config.new if @config == Config.global || @config.frozen?
|
23
27
|
end
|
24
28
|
|
25
29
|
# :call-seq:
|
@@ -321,6 +325,24 @@ module Net
|
|
321
325
|
SEQUENCE_SET = /#{SEQUENCE_SET_ITEM}(?:,#{SEQUENCE_SET_ITEM})*/n
|
322
326
|
SEQUENCE_SET_STR = /\A#{SEQUENCE_SET}\z/n
|
323
327
|
|
328
|
+
# partial-range-first = nz-number ":" nz-number
|
329
|
+
# ;; Request to search from oldest (lowest UIDs) to
|
330
|
+
# ;; more recent messages.
|
331
|
+
# ;; A range 500:400 is the same as 400:500.
|
332
|
+
# ;; This is similar to <seq-range> from [RFC3501]
|
333
|
+
# ;; but cannot contain "*".
|
334
|
+
PARTIAL_RANGE_FIRST = /\A(#{NZ_NUMBER}):(#{NZ_NUMBER})\z/n
|
335
|
+
|
336
|
+
# partial-range-last = MINUS nz-number ":" MINUS nz-number
|
337
|
+
# ;; Request to search from newest (highest UIDs) to
|
338
|
+
# ;; oldest messages.
|
339
|
+
# ;; A range -500:-400 is the same as -400:-500.
|
340
|
+
PARTIAL_RANGE_LAST = /\A(-#{NZ_NUMBER}):(-#{NZ_NUMBER})\z/n
|
341
|
+
|
342
|
+
# partial-range = partial-range-first / partial-range-last
|
343
|
+
PARTIAL_RANGE = Regexp.union(PARTIAL_RANGE_FIRST,
|
344
|
+
PARTIAL_RANGE_LAST)
|
345
|
+
|
324
346
|
# RFC3501:
|
325
347
|
# literal = "{" number "}" CRLF *CHAR8
|
326
348
|
# ; Number represents the number of CHAR8s
|
@@ -716,7 +738,7 @@ module Net
|
|
716
738
|
when "EXISTS" then mailbox_data__exists # RFC3501, RFC9051
|
717
739
|
when "ESEARCH" then esearch_response # RFC4731, RFC9051, etc
|
718
740
|
when "VANISHED" then expunged_resp # RFC7162
|
719
|
-
when "UIDFETCH" then uidfetch_resp #
|
741
|
+
when "UIDFETCH" then uidfetch_resp # RFC9586
|
720
742
|
when "SEARCH" then mailbox_data__search # RFC3501 (obsolete)
|
721
743
|
when "CAPABILITY" then capability_data__untagged # RFC3501, RFC9051
|
722
744
|
when "FLAGS" then mailbox_data__flags # RFC3501, RFC9051
|
@@ -769,9 +791,6 @@ module Net
|
|
769
791
|
def response_data__ignored; response_data__unhandled(IgnoredResponse) end
|
770
792
|
alias response_data__noop response_data__ignored
|
771
793
|
|
772
|
-
alias esearch_response response_data__unhandled
|
773
|
-
alias expunged_resp response_data__unhandled
|
774
|
-
alias uidfetch_resp response_data__unhandled
|
775
794
|
alias listrights_data response_data__unhandled
|
776
795
|
alias myrights_data response_data__unhandled
|
777
796
|
alias metadata_resp response_data__unhandled
|
@@ -832,6 +851,14 @@ module Net
|
|
832
851
|
UntaggedResponse.new(name, data, @str)
|
833
852
|
end
|
834
853
|
|
854
|
+
# uidfetch-resp = uniqueid SP "UIDFETCH" SP msg-att
|
855
|
+
def uidfetch_resp
|
856
|
+
uid = uniqueid; SP!
|
857
|
+
name = label "UIDFETCH"; SP!
|
858
|
+
data = UIDFetchData.new(uid, msg_att(uid))
|
859
|
+
UntaggedResponse.new(name, data, @str)
|
860
|
+
end
|
861
|
+
|
835
862
|
def response_data__simple_numeric
|
836
863
|
data = nz_number; SP!
|
837
864
|
name = tagged_ext_label
|
@@ -842,6 +869,20 @@ module Net
|
|
842
869
|
alias mailbox_data__exists response_data__simple_numeric
|
843
870
|
alias mailbox_data__recent response_data__simple_numeric
|
844
871
|
|
872
|
+
# The name for this is confusing, because it *replaces* EXPUNGE
|
873
|
+
# >>>
|
874
|
+
# expunged-resp = "VANISHED" [SP "(EARLIER)"] SP known-uids
|
875
|
+
def expunged_resp
|
876
|
+
name = label "VANISHED"; SP!
|
877
|
+
earlier = if lpar? then label("EARLIER"); rpar; SP!; true else false end
|
878
|
+
uids = known_uids
|
879
|
+
data = VanishedData[uids, earlier]
|
880
|
+
UntaggedResponse.new name, data, @str
|
881
|
+
end
|
882
|
+
|
883
|
+
# TODO: replace with uid_set
|
884
|
+
alias known_uids sequence_set
|
885
|
+
|
845
886
|
# RFC3501 & RFC9051:
|
846
887
|
# msg-att = "(" (msg-att-dynamic / msg-att-static)
|
847
888
|
# *(SP (msg-att-dynamic / msg-att-static)) ")"
|
@@ -1468,6 +1509,111 @@ module Net
|
|
1468
1509
|
end
|
1469
1510
|
alias sort_data mailbox_data__search
|
1470
1511
|
|
1512
|
+
# esearch-response = "ESEARCH" [search-correlator] [SP "UID"]
|
1513
|
+
# *(SP search-return-data)
|
1514
|
+
# ;; Note that SEARCH and ESEARCH responses
|
1515
|
+
# ;; SHOULD be mutually exclusive,
|
1516
|
+
# ;; i.e., only one of the response types
|
1517
|
+
# ;; should be
|
1518
|
+
# ;; returned as a result of a command.
|
1519
|
+
# esearch-response = "ESEARCH" [search-correlator] [SP "UID"]
|
1520
|
+
# *(SP search-return-data)
|
1521
|
+
# ; ESEARCH response replaces SEARCH response
|
1522
|
+
# ; from IMAP4rev1.
|
1523
|
+
# search-correlator = SP "(" "TAG" SP tag-string ")"
|
1524
|
+
def esearch_response
|
1525
|
+
name = label("ESEARCH")
|
1526
|
+
tag = search_correlator if peek_str?(" (")
|
1527
|
+
uid = peek_re?(/\G UID\b/i) && (SP!; label("UID"); true)
|
1528
|
+
data = []
|
1529
|
+
data << search_return_data while SP?
|
1530
|
+
esearch = ESearchResult.new(tag, uid, data)
|
1531
|
+
UntaggedResponse.new(name, esearch, @str)
|
1532
|
+
end
|
1533
|
+
|
1534
|
+
# From RFC4731 (ESEARCH):
|
1535
|
+
# search-return-data = "MIN" SP nz-number /
|
1536
|
+
# "MAX" SP nz-number /
|
1537
|
+
# "ALL" SP sequence-set /
|
1538
|
+
# "COUNT" SP number /
|
1539
|
+
# search-ret-data-ext
|
1540
|
+
# ; All return data items conform to
|
1541
|
+
# ; search-ret-data-ext syntax.
|
1542
|
+
# search-ret-data-ext = search-modifier-name SP search-return-value
|
1543
|
+
# search-modifier-name = tagged-ext-label
|
1544
|
+
# search-return-value = tagged-ext-val
|
1545
|
+
#
|
1546
|
+
# From RFC4731 (ESEARCH):
|
1547
|
+
# search-return-data =/ "MODSEQ" SP mod-sequence-value
|
1548
|
+
#
|
1549
|
+
# From RFC9394 (PARTIAL):
|
1550
|
+
# search-return-data =/ ret-data-partial
|
1551
|
+
#
|
1552
|
+
def search_return_data
|
1553
|
+
label = search_modifier_name; SP!
|
1554
|
+
value =
|
1555
|
+
case label
|
1556
|
+
when "MIN" then nz_number
|
1557
|
+
when "MAX" then nz_number
|
1558
|
+
when "ALL" then sequence_set
|
1559
|
+
when "COUNT" then number
|
1560
|
+
when "MODSEQ" then mod_sequence_value # RFC7162: CONDSTORE
|
1561
|
+
when "PARTIAL" then ret_data_partial__value # RFC9394: PARTIAL
|
1562
|
+
else search_return_value
|
1563
|
+
end
|
1564
|
+
[label, value]
|
1565
|
+
end
|
1566
|
+
|
1567
|
+
# From RFC5267 (CONTEXT=SEARCH, CONTEXT=SORT) and RFC9394 (PARTIAL):
|
1568
|
+
# ret-data-partial = "PARTIAL"
|
1569
|
+
# SP "(" partial-range SP partial-results ")"
|
1570
|
+
def ret_data_partial__value
|
1571
|
+
lpar
|
1572
|
+
range = partial_range; SP!
|
1573
|
+
results = partial_results
|
1574
|
+
rpar
|
1575
|
+
ESearchResult::PartialResult.new(range, results)
|
1576
|
+
end
|
1577
|
+
|
1578
|
+
# partial-range = partial-range-first / partial-range-last
|
1579
|
+
# tagged-ext-simple =/ partial-range-last
|
1580
|
+
def partial_range
|
1581
|
+
case (str = atom)
|
1582
|
+
when Patterns::PARTIAL_RANGE_FIRST, Patterns::PARTIAL_RANGE_LAST
|
1583
|
+
min, max = [Integer($1), Integer($2)].minmax
|
1584
|
+
min..max
|
1585
|
+
else
|
1586
|
+
parse_error("unexpected atom %p, expected partial-range", str)
|
1587
|
+
end
|
1588
|
+
end
|
1589
|
+
|
1590
|
+
# partial-results = sequence-set / "NIL"
|
1591
|
+
# ;; <sequence-set> from [RFC3501].
|
1592
|
+
# ;; NIL indicates that no results correspond to
|
1593
|
+
# ;; the requested range.
|
1594
|
+
def partial_results; NIL? ? nil : sequence_set end
|
1595
|
+
|
1596
|
+
# search-modifier-name = tagged-ext-label
|
1597
|
+
alias search_modifier_name tagged_ext_label
|
1598
|
+
|
1599
|
+
# search-return-value = tagged-ext-val
|
1600
|
+
# ; Data for the returned search option.
|
1601
|
+
# ; A single "nz-number"/"number"/"number64" value
|
1602
|
+
# ; can be returned as an atom (i.e., without
|
1603
|
+
# ; quoting). A sequence-set can be returned
|
1604
|
+
# ; as an atom as well.
|
1605
|
+
def search_return_value; ExtensionData.new(tagged_ext_val) end
|
1606
|
+
|
1607
|
+
# search-correlator = SP "(" "TAG" SP tag-string ")"
|
1608
|
+
def search_correlator
|
1609
|
+
SP!; lpar; label("TAG"); SP!; tag = tag_string; rpar
|
1610
|
+
tag
|
1611
|
+
end
|
1612
|
+
|
1613
|
+
# tag-string = astring
|
1614
|
+
# ; <tag> represented as <astring>
|
1615
|
+
alias tag_string astring
|
1616
|
+
|
1471
1617
|
# RFC5256: THREAD
|
1472
1618
|
# thread-data = "THREAD" [SP 1*thread-list]
|
1473
1619
|
def thread_data
|
@@ -1800,6 +1946,9 @@ module Net
|
|
1800
1946
|
#
|
1801
1947
|
# RFC8474: OBJECTID
|
1802
1948
|
# resp-text-code =/ "MAILBOXID" SP "(" objectid ")"
|
1949
|
+
#
|
1950
|
+
# RFC9586: UIDONLY
|
1951
|
+
# resp-text-code =/ "UIDREQUIRED"
|
1803
1952
|
def resp_text_code
|
1804
1953
|
name = resp_text_code__name
|
1805
1954
|
data =
|
@@ -1822,6 +1971,7 @@ module Net
|
|
1822
1971
|
when "HIGHESTMODSEQ" then SP!; mod_sequence_value # CONDSTORE
|
1823
1972
|
when "MODIFIED" then SP!; sequence_set # CONDSTORE
|
1824
1973
|
when "MAILBOXID" then SP!; parens__objectid # RFC8474: OBJECTID
|
1974
|
+
when "UIDREQUIRED" then # RFC9586: UIDONLY
|
1825
1975
|
else
|
1826
1976
|
SP? and text_chars_except_rbra
|
1827
1977
|
end
|
@@ -1851,11 +2001,10 @@ module Net
|
|
1851
2001
|
#
|
1852
2002
|
# n.b, uniqueid ⊂ uid-set. To avoid inconsistent return types, we always
|
1853
2003
|
# match uid_set even if that returns a single-member array.
|
1854
|
-
#
|
1855
2004
|
def resp_code_apnd__data
|
1856
2005
|
validity = number; SP!
|
1857
2006
|
dst_uids = uid_set # uniqueid ⊂ uid-set
|
1858
|
-
|
2007
|
+
AppendUID(validity, dst_uids)
|
1859
2008
|
end
|
1860
2009
|
|
1861
2010
|
# already matched: "COPYUID"
|
@@ -1865,7 +2014,25 @@ module Net
|
|
1865
2014
|
validity = number; SP!
|
1866
2015
|
src_uids = uid_set; SP!
|
1867
2016
|
dst_uids = uid_set
|
1868
|
-
|
2017
|
+
CopyUID(validity, src_uids, dst_uids)
|
2018
|
+
end
|
2019
|
+
|
2020
|
+
def AppendUID(...) DeprecatedUIDPlus(...) || AppendUIDData.new(...) end
|
2021
|
+
def CopyUID(...) DeprecatedUIDPlus(...) || CopyUIDData.new(...) end
|
2022
|
+
|
2023
|
+
# TODO: remove this code in the v0.6.0 release
|
2024
|
+
def DeprecatedUIDPlus(validity, src_uids = nil, dst_uids)
|
2025
|
+
return unless config.parser_use_deprecated_uidplus_data
|
2026
|
+
compact_uid_sets = [src_uids, dst_uids].compact
|
2027
|
+
count = compact_uid_sets.map { _1.count_with_duplicates }.max
|
2028
|
+
max = config.parser_max_deprecated_uidplus_data_size
|
2029
|
+
if count <= max
|
2030
|
+
src_uids &&= src_uids.each_ordered_number.to_a
|
2031
|
+
dst_uids = dst_uids.each_ordered_number.to_a
|
2032
|
+
UIDPlusData.new(validity, src_uids, dst_uids)
|
2033
|
+
elsif config.parser_use_deprecated_uidplus_data != :up_to_max_size
|
2034
|
+
parse_error("uid-set is too large: %d > %d", count, max)
|
2035
|
+
end
|
1869
2036
|
end
|
1870
2037
|
|
1871
2038
|
ADDRESS_REGEXP = /\G
|
@@ -1991,15 +2158,9 @@ module Net
|
|
1991
2158
|
# uniqueid = nz-number
|
1992
2159
|
# ; Strictly ascending
|
1993
2160
|
def uid_set
|
1994
|
-
|
1995
|
-
|
1996
|
-
|
1997
|
-
when T_ATOM
|
1998
|
-
token.value.split(",").flat_map {|range|
|
1999
|
-
range = range.split(":").map {|uniqueid| Integer(uniqueid) }
|
2000
|
-
range.size == 1 ? range : Range.new(range.min, range.max).to_a
|
2001
|
-
}
|
2002
|
-
end
|
2161
|
+
set = sequence_set
|
2162
|
+
parse_error("uid-set cannot contain '*'") if set.include_star?
|
2163
|
+
set
|
2003
2164
|
end
|
2004
2165
|
|
2005
2166
|
def nil_atom
|
@@ -5,7 +5,7 @@ module Net
|
|
5
5
|
module SASL
|
6
6
|
|
7
7
|
# Authenticator for the "+ANONYMOUS+" SASL mechanism, as specified by
|
8
|
-
# RFC-4505[https://
|
8
|
+
# RFC-4505[https://www.rfc-editor.org/rfc/rfc4505]. See
|
9
9
|
# Net::IMAP#authenticate.
|
10
10
|
class AnonymousAuthenticator
|
11
11
|
|
@@ -13,7 +13,7 @@ module Net
|
|
13
13
|
# characters in length.
|
14
14
|
#
|
15
15
|
# If it contains an "@" sign, the message must be a valid email address
|
16
|
-
# (+addr-spec+ from RFC-2822[https://
|
16
|
+
# (+addr-spec+ from RFC-2822[https://www.rfc-editor.org/rfc/rfc2822]).
|
17
17
|
# Email syntax is _not_ validated by AnonymousAuthenticator.
|
18
18
|
#
|
19
19
|
# Otherwise, it can be any UTF8 string which is permitted by the
|
@@ -25,7 +25,7 @@ module Net
|
|
25
25
|
# new(anonymous_message: "", **) -> authenticator
|
26
26
|
#
|
27
27
|
# Creates an Authenticator for the "+ANONYMOUS+" SASL mechanism, as
|
28
|
-
# specified in RFC-4505[https://
|
28
|
+
# specified in RFC-4505[https://www.rfc-editor.org/rfc/rfc4505]. To use
|
29
29
|
# this, see Net::IMAP#authenticate or your client's authentication
|
30
30
|
# method.
|
31
31
|
#
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Authenticator for the "+CRAM-MD5+" SASL mechanism, specified in
|
4
|
-
# RFC2195[https://
|
4
|
+
# RFC2195[https://www.rfc-editor.org/rfc/rfc2195]. See Net::IMAP#authenticate.
|
5
5
|
#
|
6
6
|
# == Deprecated
|
7
7
|
#
|
8
8
|
# +CRAM-MD5+ is obsolete and insecure. It is included for compatibility with
|
9
9
|
# existing servers.
|
10
|
-
# {draft-ietf-sasl-crammd5-to-historic}[https://
|
10
|
+
# {draft-ietf-sasl-crammd5-to-historic}[https://www.rfc-editor.org/rfc/draft-ietf-sasl-crammd5-to-historic-00.html]
|
11
11
|
# recommends using +SCRAM-*+ or +PLAIN+ protected by TLS instead.
|
12
12
|
#
|
13
|
-
# Additionally, RFC8314[https://
|
13
|
+
# Additionally, RFC8314[https://www.rfc-editor.org/rfc/rfc8314] discourage the use
|
14
14
|
# of cleartext and recommends TLS version 1.2 or greater be used for all
|
15
15
|
# traffic. With TLS +CRAM-MD5+ is okay, but so is +PLAIN+
|
16
16
|
class Net::IMAP::SASL::CramMD5Authenticator
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Net::IMAP authenticator for the +DIGEST-MD5+ SASL mechanism type, specified
|
4
|
-
# in RFC-2831[https://
|
4
|
+
# in RFC-2831[https://www.rfc-editor.org/rfc/rfc2831]. See Net::IMAP#authenticate.
|
5
5
|
#
|
6
6
|
# == Deprecated
|
7
7
|
#
|
8
8
|
# "+DIGEST-MD5+" has been deprecated by
|
9
|
-
# RFC-6331[https://
|
9
|
+
# RFC-6331[https://www.rfc-editor.org/rfc/rfc6331] and should not be relied on for
|
10
10
|
# security. It is included for compatibility with existing servers.
|
11
11
|
class Net::IMAP::SASL::DigestMD5Authenticator
|
12
12
|
DataFormatError = Net::IMAP::DataFormatError
|
@@ -37,10 +37,10 @@ class Net::IMAP::SASL::DigestMD5Authenticator
|
|
37
37
|
|
38
38
|
# Authentication identity: the identity that matches the #password.
|
39
39
|
#
|
40
|
-
# RFC-2831[https://
|
40
|
+
# RFC-2831[https://www.rfc-editor.org/rfc/rfc2831] uses the term +username+.
|
41
41
|
# "Authentication identity" is the generic term used by
|
42
|
-
# RFC-4422[https://
|
43
|
-
# RFC-4616[https://
|
42
|
+
# RFC-4422[https://www.rfc-editor.org/rfc/rfc4422].
|
43
|
+
# RFC-4616[https://www.rfc-editor.org/rfc/rfc4616] and many later RFCs abbreviate
|
44
44
|
# this to +authcid+.
|
45
45
|
attr_reader :username
|
46
46
|
alias authcid username
|
@@ -85,7 +85,7 @@ class Net::IMAP::SASL::DigestMD5Authenticator
|
|
85
85
|
# must be set appropriately to use authenticators in other protocols.
|
86
86
|
#
|
87
87
|
# If an IANA-registered name isn't available, GSS-API
|
88
|
-
# (RFC-2743[https://
|
88
|
+
# (RFC-2743[https://www.rfc-editor.org/rfc/rfc2743]) allows the generic name
|
89
89
|
# "host".
|
90
90
|
attr_reader :service
|
91
91
|
|
@@ -93,7 +93,7 @@ class Net::IMAP::SASL::DigestMD5Authenticator
|
|
93
93
|
#
|
94
94
|
# +service_name+ will be ignored when it is +nil+ or identical to +host+.
|
95
95
|
#
|
96
|
-
# From RFC-2831[https://
|
96
|
+
# From RFC-2831[https://www.rfc-editor.org/rfc/rfc2831]:
|
97
97
|
# >>>
|
98
98
|
# The service is considered to be replicated if the client's
|
99
99
|
# service-location process involves resolution using standard DNS lookup
|
@@ -176,7 +176,7 @@ class Net::IMAP::SASL::DigestMD5Authenticator
|
|
176
176
|
@nc, @stage = {}, STAGE_ONE
|
177
177
|
end
|
178
178
|
|
179
|
-
# From RFC-2831[https://
|
179
|
+
# From RFC-2831[https://www.rfc-editor.org/rfc/rfc2831]:
|
180
180
|
# >>>
|
181
181
|
# Indicates the principal name of the service with which the client wishes
|
182
182
|
# to connect, formed from the serv-type, host, and serv-name. For
|
@@ -5,7 +5,7 @@ module Net
|
|
5
5
|
module SASL
|
6
6
|
|
7
7
|
# Authenticator for the "+EXTERNAL+" SASL mechanism, as specified by
|
8
|
-
# RFC-4422[https://
|
8
|
+
# RFC-4422[https://www.rfc-editor.org/rfc/rfc4422]. See
|
9
9
|
# Net::IMAP#authenticate.
|
10
10
|
#
|
11
11
|
# The EXTERNAL mechanism requests that the server use client credentials
|
@@ -33,7 +33,7 @@ module Net
|
|
33
33
|
# new(username = nil, **) -> authenticator
|
34
34
|
#
|
35
35
|
# Creates an Authenticator for the "+EXTERNAL+" SASL mechanism, as
|
36
|
-
# specified in RFC-4422[https://
|
36
|
+
# specified in RFC-4422[https://www.rfc-editor.org/rfc/rfc4422]. To use
|
37
37
|
# this, see Net::IMAP#authenticate or your client's authentication
|
38
38
|
# method.
|
39
39
|
#
|
@@ -5,15 +5,15 @@ module Net
|
|
5
5
|
module SASL
|
6
6
|
|
7
7
|
# Originally defined for the GS2 mechanism family in
|
8
|
-
# RFC5801[https://
|
8
|
+
# RFC5801[https://www.rfc-editor.org/rfc/rfc5801],
|
9
9
|
# several different mechanisms start with a GS2 header:
|
10
|
-
# * +GS2-*+ --- RFC5801[https://
|
11
|
-
# * +SCRAM-*+ --- RFC5802[https://
|
10
|
+
# * +GS2-*+ --- RFC5801[https://www.rfc-editor.org/rfc/rfc5801]
|
11
|
+
# * +SCRAM-*+ --- RFC5802[https://www.rfc-editor.org/rfc/rfc5802]
|
12
12
|
# (ScramAuthenticator)
|
13
|
-
# * +SAML20+ --- RFC6595[https://
|
14
|
-
# * +OPENID20+ --- RFC6616[https://
|
15
|
-
# * +OAUTH10A+ --- RFC7628[https://
|
16
|
-
# * +OAUTHBEARER+ --- RFC7628[https://
|
13
|
+
# * +SAML20+ --- RFC6595[https://www.rfc-editor.org/rfc/rfc6595]
|
14
|
+
# * +OPENID20+ --- RFC6616[https://www.rfc-editor.org/rfc/rfc6616]
|
15
|
+
# * +OAUTH10A+ --- RFC7628[https://www.rfc-editor.org/rfc/rfc7628]
|
16
|
+
# * +OAUTHBEARER+ --- RFC7628[https://www.rfc-editor.org/rfc/rfc7628]
|
17
17
|
# (OAuthBearerAuthenticator)
|
18
18
|
#
|
19
19
|
# Classes that include this module must implement +#authzid+.
|
@@ -3,9 +3,9 @@
|
|
3
3
|
# Authenticator for the "+LOGIN+" SASL mechanism. See Net::IMAP#authenticate.
|
4
4
|
#
|
5
5
|
# +LOGIN+ authentication sends the password in cleartext.
|
6
|
-
# RFC3501[https://
|
6
|
+
# RFC3501[https://www.rfc-editor.org/rfc/rfc3501] encourages servers to disable
|
7
7
|
# cleartext authentication until after TLS has been negotiated.
|
8
|
-
# RFC8314[https://
|
8
|
+
# RFC8314[https://www.rfc-editor.org/rfc/rfc8314] recommends TLS version 1.2 or
|
9
9
|
# greater be used for all traffic, and deprecate cleartext access ASAP. +LOGIN+
|
10
10
|
# can be secured by TLS encryption.
|
11
11
|
#
|
@@ -7,7 +7,7 @@ module Net
|
|
7
7
|
module SASL
|
8
8
|
|
9
9
|
# Abstract base class for the SASL mechanisms defined in
|
10
|
-
# RFC7628[https://
|
10
|
+
# RFC7628[https://www.rfc-editor.org/rfc/rfc7628]:
|
11
11
|
# * OAUTHBEARER[rdoc-ref:OAuthBearerAuthenticator]
|
12
12
|
# (OAuthBearerAuthenticator)
|
13
13
|
# * OAUTH10A
|
@@ -52,7 +52,7 @@ module Net
|
|
52
52
|
# this may hold information about the failure reason, as JSON.
|
53
53
|
attr_reader :last_server_response
|
54
54
|
|
55
|
-
# Creates an RFC7628[https://
|
55
|
+
# Creates an RFC7628[https://www.rfc-editor.org/rfc/rfc7628] OAuth
|
56
56
|
# authenticator.
|
57
57
|
#
|
58
58
|
# ==== Parameters
|
@@ -126,12 +126,12 @@ module Net
|
|
126
126
|
end
|
127
127
|
|
128
128
|
# Authenticator for the "+OAUTHBEARER+" SASL mechanism, specified in
|
129
|
-
# RFC7628[https://
|
130
|
-
# 2.0 bearer tokens, as described in
|
131
|
-
# RFC6750[https://
|
129
|
+
# RFC7628[https://www.rfc-editor.org/rfc/rfc7628]. Authenticates using
|
130
|
+
# OAuth 2.0 bearer tokens, as described in
|
131
|
+
# RFC6750[https://www.rfc-editor.org/rfc/rfc6750]. Use via
|
132
132
|
# Net::IMAP#authenticate.
|
133
133
|
#
|
134
|
-
# RFC6750[https://
|
134
|
+
# RFC6750[https://www.rfc-editor.org/rfc/rfc6750] requires Transport Layer
|
135
135
|
# Security (TLS) to secure the protocol interaction between the client and
|
136
136
|
# the resource server. TLS _MUST_ be used for +OAUTHBEARER+ to protect
|
137
137
|
# the bearer token.
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Authenticator for the "+PLAIN+" SASL mechanism, specified in
|
4
|
-
# RFC-4616[https://
|
4
|
+
# RFC-4616[https://www.rfc-editor.org/rfc/rfc4616]. See Net::IMAP#authenticate.
|
5
5
|
#
|
6
6
|
# +PLAIN+ authentication sends the password in cleartext.
|
7
|
-
# RFC-3501[https://
|
7
|
+
# RFC-3501[https://www.rfc-editor.org/rfc/rfc3501] encourages servers to disable
|
8
8
|
# cleartext authentication until after TLS has been negotiated.
|
9
|
-
# RFC-8314[https://
|
9
|
+
# RFC-8314[https://www.rfc-editor.org/rfc/rfc8314] recommends TLS version 1.2 or
|
10
10
|
# greater be used for all traffic, and deprecate cleartext access ASAP. +PLAIN+
|
11
11
|
# can be secured by TLS encryption.
|
12
12
|
class Net::IMAP::SASL::PlainAuthenticator
|
@@ -16,11 +16,11 @@ class Net::IMAP::SASL::PlainAuthenticator
|
|
16
16
|
|
17
17
|
# Authentication identity: the identity that matches the #password.
|
18
18
|
#
|
19
|
-
# RFC-2831[https://
|
19
|
+
# RFC-2831[https://www.rfc-editor.org/rfc/rfc2831] uses the term +username+.
|
20
20
|
# "Authentication identity" is the generic term used by
|
21
|
-
# RFC-4422[https://
|
22
|
-
# RFC-4616[https://
|
23
|
-
# this to +authcid+.
|
21
|
+
# RFC-4422[https://www.rfc-editor.org/rfc/rfc4422].
|
22
|
+
# RFC-4616[https://www.rfc-editor.org/rfc/rfc4616] and many later RFCs
|
23
|
+
# abbreviate this to +authcid+.
|
24
24
|
attr_reader :username
|
25
25
|
alias authcid username
|
26
26
|
|
@@ -11,7 +11,7 @@ module Net
|
|
11
11
|
module SASL
|
12
12
|
|
13
13
|
# Abstract base class for the "+SCRAM-*+" family of SASL mechanisms,
|
14
|
-
# defined in RFC5802[https://
|
14
|
+
# defined in RFC5802[https://www.rfc-editor.org/rfc/rfc5802]. Use via
|
15
15
|
# Net::IMAP#authenticate.
|
16
16
|
#
|
17
17
|
# Directly supported:
|
@@ -99,11 +99,11 @@ module Net
|
|
99
99
|
|
100
100
|
# Authentication identity: the identity that matches the #password.
|
101
101
|
#
|
102
|
-
# RFC-2831[https://
|
103
|
-
# "Authentication identity" is the generic term used by
|
104
|
-
# RFC-4422[https://
|
105
|
-
# RFC-4616[https://
|
106
|
-
# this to +authcid+.
|
102
|
+
# RFC-2831[https://www.rfc-editor.org/rfc/rfc2831] uses the term
|
103
|
+
# +username+. "Authentication identity" is the generic term used by
|
104
|
+
# RFC-4422[https://www.rfc-editor.org/rfc/rfc4422].
|
105
|
+
# RFC-4616[https://www.rfc-editor.org/rfc/rfc4616] and many later RFCs
|
106
|
+
# abbreviate this to +authcid+.
|
107
107
|
attr_reader :username
|
108
108
|
alias authcid username
|
109
109
|
|
@@ -263,7 +263,7 @@ module Net
|
|
263
263
|
end
|
264
264
|
|
265
265
|
# Authenticator for the "+SCRAM-SHA-1+" SASL mechanism, defined in
|
266
|
-
# RFC5802[https://
|
266
|
+
# RFC5802[https://www.rfc-editor.org/rfc/rfc5802].
|
267
267
|
#
|
268
268
|
# Uses the "SHA-1" digest algorithm from OpenSSL::Digest.
|
269
269
|
#
|
@@ -273,7 +273,7 @@ module Net
|
|
273
273
|
end
|
274
274
|
|
275
275
|
# Authenticator for the "+SCRAM-SHA-256+" SASL mechanism, defined in
|
276
|
-
# RFC7677[https://
|
276
|
+
# RFC7677[https://www.rfc-editor.org/rfc/rfc7677].
|
277
277
|
#
|
278
278
|
# Uses the "SHA-256" digest algorithm from OpenSSL::Digest.
|
279
279
|
#
|
data/lib/net/imap/sasl.rb
CHANGED
@@ -5,7 +5,7 @@ module Net
|
|
5
5
|
|
6
6
|
# Pluggable authentication mechanisms for protocols which support SASL
|
7
7
|
# (Simple Authentication and Security Layer), such as IMAP4, SMTP, LDAP, and
|
8
|
-
# XMPP. {RFC-4422}[https://
|
8
|
+
# XMPP. {RFC-4422}[https://www.rfc-editor.org/rfc/rfc4422] specifies the
|
9
9
|
# common \SASL framework:
|
10
10
|
# >>>
|
11
11
|
# SASL is conceptually a framework that provides an abstraction layer
|
@@ -100,10 +100,10 @@ module Net
|
|
100
100
|
# data.to_s("SORT") # => "* SORT 2 8 32 128 256 512"
|
101
101
|
# data.to_s(nil) # => "2 8 32 128 256 512"
|
102
102
|
#
|
103
|
-
# data = Net::IMAP::SearchResult[1, 3, 16, 1024, modseq: 2048]
|
103
|
+
# data = Net::IMAP::SearchResult[1, 3, 16, 1024, modseq: 2048]
|
104
104
|
# data.to_s # => "* SEARCH 1 3 16 1024 (MODSEQ 2048)"
|
105
105
|
# data.to_s("SORT") # => "* SORT 1 3 16 1024 (MODSEQ 2048)"
|
106
|
-
# data.to_s
|
106
|
+
# data.to_s(nil) # => "1 3 16 1024 (MODSEQ 2048)"
|
107
107
|
#
|
108
108
|
def to_s(type = "SEARCH")
|
109
109
|
str = +""
|