sup 1.2 → 1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/checks.yml +16 -2
- data/.gitmodules +1 -0
- data/History.txt +16 -0
- data/Manifest.txt +12 -1
- data/contrib/nix/Gemfile +2 -0
- data/contrib/nix/Gemfile.lock +37 -16
- data/contrib/nix/gem-install-shell.nix +2 -0
- data/contrib/nix/gemset.nix +83 -31
- data/contrib/nix/ruby2.4-Gemfile.lock +5 -1
- data/contrib/nix/ruby2.4-gemset.nix +22 -2
- data/contrib/nix/ruby2.4-shell.nix +2 -6
- data/contrib/nix/ruby2.5-Gemfile.lock +5 -1
- data/contrib/nix/ruby2.5-gemset.nix +22 -2
- data/contrib/nix/ruby2.5-shell.nix +2 -6
- data/contrib/nix/ruby2.6-Gemfile.lock +5 -1
- data/contrib/nix/ruby2.6-gemset.nix +22 -2
- data/contrib/nix/ruby2.6-shell.nix +2 -6
- data/contrib/nix/ruby2.7-Gemfile.lock +91 -0
- data/contrib/nix/ruby2.7-gemset.nix +359 -0
- data/contrib/nix/ruby2.7-shell.nix +2 -11
- data/contrib/nix/ruby3.0-Gemfile.lock +91 -0
- data/contrib/nix/ruby3.0-gemset.nix +359 -0
- data/contrib/nix/ruby3.0-shell.nix +2 -11
- data/contrib/nix/ruby3.1-shell.nix +9 -7
- data/contrib/nix/ruby3.2-shell.nix +9 -7
- data/contrib/nix/ruby3.3-shell.nix +9 -7
- data/contrib/nix/ruby3.4-shell.nix +36 -0
- data/contrib/nix/test-all-rubies.sh +1 -1
- data/lib/sup/crypto.rb +7 -5
- data/lib/sup/maildir.rb +4 -0
- data/lib/sup/mbox.rb +25 -7
- data/lib/sup/message.rb +13 -10
- data/lib/sup/modes/edit_message_mode.rb +5 -5
- data/lib/sup/util.rb +9 -2
- data/lib/sup/version.rb +1 -1
- data/man/sup-add.1 +15 -15
- data/man/sup-config.1 +9 -9
- data/man/sup-dump.1 +13 -12
- data/man/sup-import-dump.1 +20 -20
- data/man/sup-psych-ify-config-files.1 +11 -11
- data/man/sup-recover-sources.1 +18 -18
- data/man/sup-sync-back-maildir.1 +18 -17
- data/man/sup-sync.1 +29 -29
- data/man/sup-tweak-labels.1 +22 -21
- data/man/sup.1 +21 -21
- data/sup.gemspec +2 -0
- data/test/dummy_source.rb +6 -0
- data/test/fixtures/embedded-message-rfc6532.eml +33 -0
- data/test/fixtures/invalid-date.eml +8 -0
- data/test/gnupg_test_home/private-keys-v1.d/26C05E44706A8E230B3255BB9532B34DC9420232.key +42 -0
- data/test/gnupg_test_home/private-keys-v1.d/D187ADC90EC4DEB7047678EAA37E33A53A465D47.key +5 -0
- data/test/gnupg_test_home/private-keys-v1.d/FB2D9BD3B1BE90B5BCF697781F8404224B0FCF5B.key +5 -0
- data/test/gnupg_test_home/pubring.gpg +0 -0
- data/test/gnupg_test_home/receiver_pubring.gpg +0 -0
- data/test/gnupg_test_home/receiver_secring.gpg +0 -0
- data/test/gnupg_test_home/regen_keys.sh +11 -2
- data/test/gnupg_test_home/secring.gpg +0 -0
- data/test/gnupg_test_home/sup-test-2@foo.bar.asc +20 -20
- data/test/integration/test_maildir.rb +15 -1
- data/test/integration/test_mbox.rb +10 -0
- data/test/test_crypto.rb +108 -71
- data/test/test_message.rb +42 -0
- data/test/unit/test_contact.rb +1 -1
- data/test/unit/test_edit_message_mode.rb +94 -0
- data/test/unit/test_person.rb +3 -3
- data/test/unit/test_rmail_message.rb +36 -0
- data/test/unit/util/test_string.rb +3 -3
- metadata +50 -5
- data/test/gnupg_test_home/private-keys-v1.d/306D2EE90FF0014B5B9FD07E265C751791674140.key +0 -0
data/test/test_crypto.rb
CHANGED
@@ -38,14 +38,10 @@ class TestCryptoManager < Minitest::Test
|
|
38
38
|
@path = Dir.mktmpdir
|
39
39
|
Redwood::HookManager.init File.join(@path, 'hooks')
|
40
40
|
|
41
|
-
am = {:default=> {name: "test", email: @from_email, alternates: [@from_email_ecc]}}
|
41
|
+
am = {:default=> {name: +"test", email: @from_email.dup, alternates: [@from_email_ecc.dup]}}
|
42
42
|
Redwood::AccountManager.init am
|
43
43
|
|
44
44
|
Redwood::CryptoManager.init
|
45
|
-
|
46
|
-
if not CryptoManager.have_crypto?
|
47
|
-
warn "No crypto set up, crypto will not be tested. Reason: #{CryptoManager.not_working_reason}"
|
48
|
-
end
|
49
45
|
end
|
50
46
|
|
51
47
|
def teardown
|
@@ -58,90 +54,132 @@ class TestCryptoManager < Minitest::Test
|
|
58
54
|
end
|
59
55
|
|
60
56
|
def test_sign
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
57
|
+
skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
|
58
|
+
|
59
|
+
signed = CryptoManager.sign @from_email,@to_email,"ABCDEFG"
|
60
|
+
assert_instance_of RMail::Message, signed
|
61
|
+
assert_equal("multipart/signed; protocol=application/pgp-signature; micalg=pgp-sha256",
|
62
|
+
signed.header["Content-Type"])
|
63
|
+
assert_equal "ABCDEFG", signed.body[0]
|
64
|
+
assert signed.body[1].body.length > 0 , "signature length must be > 0"
|
65
|
+
assert (signed.body[1].body.include? "-----BEGIN PGP SIGNATURE-----") , "Expecting PGP armored data"
|
70
66
|
end
|
71
67
|
|
72
68
|
def test_sign_nested_parts
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
69
|
+
skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
|
70
|
+
|
71
|
+
body = RMail::Message.new
|
72
|
+
body.header["Content-Disposition"] = +"inline"
|
73
|
+
body.body = "ABCDEFG"
|
74
|
+
payload = RMail::Message.new
|
75
|
+
payload.header["MIME-Version"] = +"1.0"
|
76
|
+
payload.add_part body
|
77
|
+
payload.add_part RMail::Message.make_attachment "attachment", "text/plain", nil, "attachment.txt"
|
78
|
+
signed = CryptoManager.sign @from_email, @to_email, payload
|
79
|
+
## The result is a multipart/signed containing a multipart/mixed.
|
80
|
+
## There should be a MIME-Version header on the top-level
|
81
|
+
## multipart/signed message, but *not* on the enclosed
|
82
|
+
## multipart/mixed part.
|
83
|
+
assert_equal 1, signed.to_s.scan(/MIME-Version:/).size
|
88
84
|
end
|
89
85
|
|
90
86
|
def test_encrypt
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
87
|
+
skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
|
88
|
+
|
89
|
+
encrypted = CryptoManager.encrypt @from_email, [@to_email], "ABCDEFG"
|
90
|
+
assert_instance_of RMail::Message, encrypted
|
91
|
+
assert (encrypted.body[1].body.include? "-----BEGIN PGP MESSAGE-----") , "Expecting PGP armored data"
|
96
92
|
end
|
97
93
|
|
98
94
|
def test_sign_and_encrypt
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
95
|
+
skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
|
96
|
+
|
97
|
+
encrypted = CryptoManager.sign_and_encrypt @from_email, [@to_email], "ABCDEFG"
|
98
|
+
assert_instance_of RMail::Message, encrypted
|
99
|
+
assert (encrypted.body[1].body.include? "-----BEGIN PGP MESSAGE-----") , "Expecting PGP armored data"
|
104
100
|
end
|
105
101
|
|
106
102
|
def test_decrypt
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
103
|
+
skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
|
104
|
+
|
105
|
+
encrypted = CryptoManager.encrypt @from_email, [@to_email], "ABCDEFG"
|
106
|
+
assert_instance_of RMail::Message, encrypted
|
107
|
+
assert_instance_of String, (encrypted.body[1].body)
|
108
|
+
decrypted = CryptoManager.decrypt encrypted.body[1], true
|
109
|
+
assert_instance_of Array, decrypted
|
110
|
+
assert_instance_of Chunk::CryptoNotice, decrypted[0]
|
111
|
+
assert_instance_of Chunk::CryptoNotice, decrypted[1]
|
112
|
+
assert_instance_of RMail::Message, decrypted[2]
|
113
|
+
assert_equal "ABCDEFG" , decrypted[2].body
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_decrypt_and_verify
|
117
|
+
skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
|
118
|
+
|
119
|
+
encrypted = CryptoManager.sign_and_encrypt @from_email, [@to_email], "ABCDEFG"
|
120
|
+
assert_instance_of RMail::Message, encrypted
|
121
|
+
assert_instance_of String, (encrypted.body[1].body)
|
122
|
+
decrypted = CryptoManager.decrypt encrypted.body[1], true
|
123
|
+
assert_instance_of Array, decrypted
|
124
|
+
assert_instance_of Chunk::CryptoNotice, decrypted[0]
|
125
|
+
assert_instance_of Chunk::CryptoNotice, decrypted[1]
|
126
|
+
assert_instance_of RMail::Message, decrypted[2]
|
127
|
+
assert_match(/^Signature made .* using RSA key ID 072B50BE/,
|
128
|
+
decrypted[1].lines[0])
|
129
|
+
assert_equal "Good signature from \"#{@from_email}\"", decrypted[1].lines[1]
|
130
|
+
assert_equal "ABCDEFG" , decrypted[2].body
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_decrypt_and_verify_nondefault_key
|
134
|
+
skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
|
135
|
+
|
136
|
+
encrypted = CryptoManager.sign_and_encrypt @from_email_ecc, [@to_email], "ABCDEFG"
|
137
|
+
assert_instance_of RMail::Message, encrypted
|
138
|
+
assert_instance_of String, (encrypted.body[1].body)
|
139
|
+
decrypted = CryptoManager.decrypt encrypted.body[1], true
|
140
|
+
assert_instance_of Array, decrypted
|
141
|
+
assert_instance_of Chunk::CryptoNotice, decrypted[0]
|
142
|
+
assert_instance_of Chunk::CryptoNotice, decrypted[1]
|
143
|
+
assert_instance_of RMail::Message, decrypted[2]
|
144
|
+
assert_match(/^Signature made .* key ID AC34B83C/, decrypted[1].lines[0])
|
145
|
+
assert_equal "Good signature from \"#{@from_email_ecc}\"", decrypted[1].lines[1]
|
146
|
+
assert_equal "ABCDEFG" , decrypted[2].body
|
118
147
|
end
|
119
148
|
|
120
149
|
def test_verify
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
150
|
+
skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
|
151
|
+
|
152
|
+
signed = CryptoManager.sign @from_email, @to_email, "ABCDEFG"
|
153
|
+
assert_instance_of RMail::Message, signed
|
154
|
+
assert_instance_of String, (signed.body[1].body)
|
155
|
+
chunk = CryptoManager.verify signed.body[0], signed.body[1], true
|
156
|
+
assert_instance_of Redwood::Chunk::CryptoNotice, chunk
|
157
|
+
assert_match(/^Signature made .* using RSA key ID 072B50BE/,
|
158
|
+
chunk.lines[0])
|
159
|
+
assert_equal "Good signature from \"#{@from_email}\"", chunk.lines[1]
|
127
160
|
end
|
128
161
|
|
129
162
|
def test_verify_unknown_keytype
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
163
|
+
skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
|
164
|
+
|
165
|
+
signed = CryptoManager.sign @from_email_ecc, @to_email, "ABCDEFG"
|
166
|
+
assert_instance_of RMail::Message, signed
|
167
|
+
assert_instance_of String, (signed.body[1].body)
|
168
|
+
chunk = CryptoManager.verify signed.body[0], signed.body[1], true
|
169
|
+
assert_instance_of Redwood::Chunk::CryptoNotice, chunk
|
170
|
+
assert_match(/^Signature made .* using unknown key type \(303\) key ID AC34B83C/,
|
171
|
+
chunk.lines[0])
|
172
|
+
assert_equal "Good signature from \"#{@from_email_ecc}\"", chunk.lines[1]
|
136
173
|
end
|
137
174
|
|
138
175
|
def test_verify_nested_parts
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
176
|
+
skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
|
177
|
+
|
178
|
+
## Generate a multipart/signed containing a multipart/mixed.
|
179
|
+
## We will test verifying the generated signature below.
|
180
|
+
## Importantly, the inner multipart/mixed does *not* have a
|
181
|
+
## MIME-Version header because it is not a top-level message.
|
182
|
+
payload = RMail::Parser.read <<EOS
|
145
183
|
Content-Type: multipart/mixed; boundary="=-1652088224-7794-561531-1825-1-="
|
146
184
|
|
147
185
|
|
@@ -156,9 +194,8 @@ Content-Type: text/plain; name="attachment.txt"
|
|
156
194
|
attachment
|
157
195
|
--=-1652088224-7794-561531-1825-1-=--
|
158
196
|
EOS
|
159
|
-
|
160
|
-
|
161
|
-
end
|
197
|
+
signed = CryptoManager.sign @from_email_ecc, @to_email, payload
|
198
|
+
CryptoManager.verify payload, signed.body[1], true
|
162
199
|
end
|
163
200
|
end
|
164
201
|
|
data/test/test_message.rb
CHANGED
@@ -344,6 +344,35 @@ class TestMessage < Minitest::Test
|
|
344
344
|
assert_equal("Second line.", chunks[2].lines[1])
|
345
345
|
end
|
346
346
|
|
347
|
+
def test_embedded_message_rfc6532
|
348
|
+
source = DummySource.new("sup-test://test_embedded_message_rfc6532")
|
349
|
+
source.messages = [ fixture_path("embedded-message-rfc6532.eml") ]
|
350
|
+
|
351
|
+
sup_message = Message.build_from_source(source, 0)
|
352
|
+
|
353
|
+
chunks = sup_message.load_from_source!
|
354
|
+
assert_equal(3, chunks.length)
|
355
|
+
|
356
|
+
assert_equal("Email with embedded message", sup_message.subj)
|
357
|
+
|
358
|
+
assert(chunks[0].is_a? Redwood::Chunk::Text)
|
359
|
+
assert_equal("Example outer message.", chunks[0].lines[0])
|
360
|
+
|
361
|
+
assert(chunks[1].is_a? Redwood::Chunk::EnclosedMessage)
|
362
|
+
assert_equal(4, chunks[1].lines.length)
|
363
|
+
assert_equal("From: Embed sender <embed@example.com>", chunks[1].lines[0])
|
364
|
+
assert_equal("To: rcpt2 <rcpt2@example.invalid>", chunks[1].lines[1])
|
365
|
+
assert_equal("Date: ", chunks[1].lines[2][0..5])
|
366
|
+
assert_equal(
|
367
|
+
Time.rfc2822("Sun, 12 May 2024 17:34:29 +1000"),
|
368
|
+
Time.rfc2822(chunks[1].lines[2][6..-1])
|
369
|
+
)
|
370
|
+
assert_equal("Subject: Embedded subject line with emoji ✨", chunks[1].lines[3])
|
371
|
+
|
372
|
+
assert(chunks[2].is_a? Redwood::Chunk::Text)
|
373
|
+
assert_equal("Example embedded message, with UTF-8 headers.", chunks[2].lines[0])
|
374
|
+
end
|
375
|
+
|
347
376
|
def test_malicious_attachment_names
|
348
377
|
source = DummySource.new("sup-test://test_blank_header_lines")
|
349
378
|
source.messages = [ fixture_path('malicious-attachment-names.eml') ]
|
@@ -359,6 +388,19 @@ class TestMessage < Minitest::Test
|
|
359
388
|
fn = chunks[3].safe_filename
|
360
389
|
assert_equal(fn, File.basename(fn))
|
361
390
|
end
|
391
|
+
|
392
|
+
def test_invalid_date_header
|
393
|
+
fallback_date = Time.utc 2024, 5, 12, 15, 5, 56
|
394
|
+
source = DummySource.new("sup-test://test_invalid_date_header")
|
395
|
+
source.messages = [ fixture_path("invalid-date.eml") ]
|
396
|
+
source.fallback_date = fallback_date
|
397
|
+
|
398
|
+
sup_message = Message.build_from_source(source, 0)
|
399
|
+
sup_message.load_from_source!
|
400
|
+
|
401
|
+
assert_equal(fallback_date, sup_message.date)
|
402
|
+
end
|
403
|
+
|
362
404
|
# TODO: test different error cases, malformed messages etc.
|
363
405
|
|
364
406
|
# TODO: test different quoting styles, see that they are all divided
|
data/test/unit/test_contact.rb
CHANGED
@@ -6,7 +6,7 @@ module Redwood
|
|
6
6
|
class TestContact < Minitest::Test
|
7
7
|
def setup
|
8
8
|
@contact = ContactManager.init(File.expand_path("../../fixtures/contacts.txt", __FILE__))
|
9
|
-
@person = Person.new "Terrible Name", "terrible@name.com"
|
9
|
+
@person = Person.new (+"Terrible Name"), (+"terrible@name.com")
|
10
10
|
end
|
11
11
|
|
12
12
|
def teardown
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "sup"
|
4
|
+
|
5
|
+
class DummySelector
|
6
|
+
attr_accessor :val
|
7
|
+
def initialize val
|
8
|
+
@val = val
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class DummyCryptoManager
|
13
|
+
def have_crypto?; true; end
|
14
|
+
def sign from, to, payload
|
15
|
+
envelope = RMail::Message.new
|
16
|
+
envelope.header["Content-Type"] = +"multipart/signed; protocol=testdummy"
|
17
|
+
envelope.add_part payload
|
18
|
+
envelope
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class TestEditMessageMode < Minitest::Test
|
23
|
+
def setup
|
24
|
+
$config = {}
|
25
|
+
@path = Dir.mktmpdir
|
26
|
+
Redwood::HookManager.init File.join(@path, "hooks")
|
27
|
+
Redwood::AccountManager.init :default => {name: +"test", email: +"sender@example.invalid"}
|
28
|
+
Redwood::CryptoManager.instance_variable_set :@instance, DummyCryptoManager.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def teardown
|
32
|
+
Redwood::CryptoManager.deinstantiate!
|
33
|
+
Redwood::AccountManager.deinstantiate!
|
34
|
+
Redwood::HookManager.deinstantiate!
|
35
|
+
FileUtils.rm_r @path
|
36
|
+
$config = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_attachment_content_transfer_encoding
|
40
|
+
## RMail::Message#make_attachment will choose
|
41
|
+
## Content-Transfer-Encoding: 8bit for a CSV file.
|
42
|
+
## If we're not GPG signing or encrypting then the attachment will be sent
|
43
|
+
## as is. Note this assumes the SMTP servers in the delivery path all
|
44
|
+
## support the 8BITMIME extension.
|
45
|
+
attachment_content = "löl,\ntest,\n"
|
46
|
+
attachment_filename = File.join @path, "dummy.csv"
|
47
|
+
File.write attachment_filename, attachment_content
|
48
|
+
|
49
|
+
opts = {
|
50
|
+
:header => {
|
51
|
+
"From" => +"sender@example.invalid",
|
52
|
+
"To" => +"recip@example.invalid",
|
53
|
+
},
|
54
|
+
:attachments => {
|
55
|
+
"dummy.csv" => RMail::Message.make_file_attachment(attachment_filename),
|
56
|
+
},
|
57
|
+
}
|
58
|
+
mode = Redwood::EditMessageMode.new opts
|
59
|
+
|
60
|
+
msg = mode.send :build_message, Time.now
|
61
|
+
attachment = msg.part(1)
|
62
|
+
assert_equal attachment_content, attachment.body
|
63
|
+
assert_equal "8bit", attachment.header["Content-Transfer-Encoding"]
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_attachment_content_transfer_encoding_signed
|
67
|
+
attachment_filename = File.join @path, "dummy.csv"
|
68
|
+
## Include some high bytes in the attachment contents in order to
|
69
|
+
## exercise quote-printable transfer encoding.
|
70
|
+
File.write attachment_filename, "löl,\ntest,\n"
|
71
|
+
|
72
|
+
opts = {
|
73
|
+
:header => {
|
74
|
+
"From" => +"sender@example.invalid",
|
75
|
+
"To" => +"recip@example.invalid",
|
76
|
+
},
|
77
|
+
:attachments => {
|
78
|
+
"dummy.csv" => RMail::Message.make_file_attachment(attachment_filename),
|
79
|
+
},
|
80
|
+
}
|
81
|
+
mode = Redwood::EditMessageMode.new opts
|
82
|
+
mode.instance_variable_set :@crypto_selector, DummySelector.new(:sign)
|
83
|
+
|
84
|
+
msg = mode.send :build_message, Time.now
|
85
|
+
## The outermost message is a (fake) multipart/signed created by DummyCryptoManager#send.
|
86
|
+
## Inside that we have our inline message at index 0 and CSV attachment at index 1.
|
87
|
+
attachment = msg.part(0).part(1)
|
88
|
+
## The attachment should have been re-encoded as quoted-printable for GPG signing.
|
89
|
+
assert_equal "l=C3=B6l,\ntest,\n", attachment.body
|
90
|
+
## There shouldn't be multiple Content-Transfer-Encoding headers.
|
91
|
+
## This was: https://github.com/sup-heliotrope/sup/issues/502
|
92
|
+
assert_equal ["quoted-printable"], attachment.header.fetch_all("Content-Transfer-Encoding")
|
93
|
+
end
|
94
|
+
end
|
data/test/unit/test_person.rb
CHANGED
@@ -5,12 +5,12 @@ module Redwood
|
|
5
5
|
|
6
6
|
class TestPerson < Minitest::Test
|
7
7
|
def setup
|
8
|
-
@person = Person.new("Thomassen, Bob", "bob@thomassen.com")
|
9
|
-
@no_name = Person.new(nil, "alice@alice.com")
|
8
|
+
@person = Person.new(+"Thomassen, Bob", +"bob@thomassen.com")
|
9
|
+
@no_name = Person.new(nil, +"alice@alice.com")
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_email_must_be_supplied
|
13
|
-
assert_raises (ArgumentError) { Person.new("Alice", nil) }
|
13
|
+
assert_raises (ArgumentError) { Person.new(+"Alice", nil) }
|
14
14
|
end
|
15
15
|
|
16
16
|
def test_to_string
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "sup"
|
4
|
+
|
5
|
+
class TestRMailMessage < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@path = Dir.mktmpdir
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
FileUtils.rm_r @path
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_make_file_attachment
|
15
|
+
filename = File.join @path, "test.html"
|
16
|
+
File.write filename, "<html></html>"
|
17
|
+
|
18
|
+
a = RMail::Message.make_file_attachment(filename)
|
19
|
+
assert_equal "text/html; name=\"test.html\"", a.header["Content-Type"]
|
20
|
+
assert_equal "attachment; filename=\"test.html\"", a.header["Content-Disposition"]
|
21
|
+
assert_equal "8bit", a.header["Content-Transfer-Encoding"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_make_file_attachment_text_with_long_lines
|
25
|
+
filename = File.join @path, "test.html"
|
26
|
+
File.write filename, "a" * 1023
|
27
|
+
|
28
|
+
a = RMail::Message.make_file_attachment(filename)
|
29
|
+
assert_equal "text/html; name=\"test.html\"", a.header["Content-Type"]
|
30
|
+
assert_equal "attachment; filename=\"test.html\"", a.header["Content-Disposition"]
|
31
|
+
assert_equal "quoted-printable", a.header["Content-Transfer-Encoding"]
|
32
|
+
|
33
|
+
qp_encoded = ("a" * 73 + "=\n") * 14 + "a=\n"
|
34
|
+
assert_equal qp_encoded, a.body
|
35
|
+
end
|
36
|
+
end
|
@@ -18,7 +18,7 @@ describe "Sup's String extension" do
|
|
18
18
|
|
19
19
|
it "calculates display length of a string" do
|
20
20
|
data.each do |(str, length)|
|
21
|
-
assert_equal length, str.display_length
|
21
|
+
assert_equal length, str.dup.display_length
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -36,7 +36,7 @@ describe "Sup's String extension" do
|
|
36
36
|
|
37
37
|
it "slices string by display length" do
|
38
38
|
data.each do |(str, length, sliced)|
|
39
|
-
assert_equal sliced, str.slice_by_display_length(length)
|
39
|
+
assert_equal sliced, str.dup.slice_by_display_length(length)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -56,7 +56,7 @@ describe "Sup's String extension" do
|
|
56
56
|
|
57
57
|
it "wraps string by display length" do
|
58
58
|
data.each do |(str, length, wrapped)|
|
59
|
-
assert_equal wrapped, str.wrap(length)
|
59
|
+
assert_equal wrapped, str.dup.wrap(length)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Morgan
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2025-04-21 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: ncursesw
|
@@ -159,6 +159,34 @@ dependencies:
|
|
159
159
|
- - ">="
|
160
160
|
- !ruby/object:Gem::Version
|
161
161
|
version: '0'
|
162
|
+
- !ruby/object:Gem::Dependency
|
163
|
+
name: benchmark
|
164
|
+
requirement: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
type: :runtime
|
170
|
+
prerelease: false
|
171
|
+
version_requirements: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
- !ruby/object:Gem::Dependency
|
177
|
+
name: fiddle
|
178
|
+
requirement: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
type: :runtime
|
184
|
+
prerelease: false
|
185
|
+
version_requirements: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
162
190
|
- !ruby/object:Gem::Dependency
|
163
191
|
name: bundler
|
164
192
|
requirement: !ruby/object:Gem::Requirement
|
@@ -336,11 +364,16 @@ files:
|
|
336
364
|
- contrib/nix/ruby2.6-Gemfile.lock
|
337
365
|
- contrib/nix/ruby2.6-gemset.nix
|
338
366
|
- contrib/nix/ruby2.6-shell.nix
|
367
|
+
- contrib/nix/ruby2.7-Gemfile.lock
|
368
|
+
- contrib/nix/ruby2.7-gemset.nix
|
339
369
|
- contrib/nix/ruby2.7-shell.nix
|
370
|
+
- contrib/nix/ruby3.0-Gemfile.lock
|
371
|
+
- contrib/nix/ruby3.0-gemset.nix
|
340
372
|
- contrib/nix/ruby3.0-shell.nix
|
341
373
|
- contrib/nix/ruby3.1-shell.nix
|
342
374
|
- contrib/nix/ruby3.2-shell.nix
|
343
375
|
- contrib/nix/ruby3.3-shell.nix
|
376
|
+
- contrib/nix/ruby3.4-shell.nix
|
344
377
|
- contrib/nix/test-all-rubies.sh
|
345
378
|
- devel/console.sh
|
346
379
|
- devel/count-loc.sh
|
@@ -435,7 +468,9 @@ files:
|
|
435
468
|
- test/fixtures/binary-content-transfer-encoding-2.eml
|
436
469
|
- test/fixtures/blank-header-fields.eml
|
437
470
|
- test/fixtures/contacts.txt
|
471
|
+
- test/fixtures/embedded-message-rfc6532.eml
|
438
472
|
- test/fixtures/embedded-message.eml
|
473
|
+
- test/fixtures/invalid-date.eml
|
439
474
|
- test/fixtures/mailing-list-header.eml
|
440
475
|
- test/fixtures/malicious-attachment-names.eml
|
441
476
|
- test/fixtures/missing-from-to.eml
|
@@ -452,7 +487,9 @@ files:
|
|
452
487
|
- test/fixtures/zimbra-quote-with-bottom-post.eml
|
453
488
|
- test/gnupg_test_home/.gpg-v21-migrated
|
454
489
|
- test/gnupg_test_home/gpg.conf
|
455
|
-
- test/gnupg_test_home/private-keys-v1.d/
|
490
|
+
- test/gnupg_test_home/private-keys-v1.d/26C05E44706A8E230B3255BB9532B34DC9420232.key
|
491
|
+
- test/gnupg_test_home/private-keys-v1.d/D187ADC90EC4DEB7047678EAA37E33A53A465D47.key
|
492
|
+
- test/gnupg_test_home/private-keys-v1.d/FB2D9BD3B1BE90B5BCF697781F8404224B0FCF5B.key
|
456
493
|
- test/gnupg_test_home/pubring.gpg
|
457
494
|
- test/gnupg_test_home/receiver_pubring.gpg
|
458
495
|
- test/gnupg_test_home/receiver_secring.gpg
|
@@ -471,9 +508,11 @@ files:
|
|
471
508
|
- test/test_yaml_regressions.rb
|
472
509
|
- test/unit/service/test_label_service.rb
|
473
510
|
- test/unit/test_contact.rb
|
511
|
+
- test/unit/test_edit_message_mode.rb
|
474
512
|
- test/unit/test_horizontal_selector.rb
|
475
513
|
- test/unit/test_locale_fiddler.rb
|
476
514
|
- test/unit/test_person.rb
|
515
|
+
- test/unit/test_rmail_message.rb
|
477
516
|
- test/unit/util/test_query.rb
|
478
517
|
- test/unit/util/test_string.rb
|
479
518
|
- test/unit/util/test_uri.rb
|
@@ -504,7 +543,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
504
543
|
- !ruby/object:Gem::Version
|
505
544
|
version: '0'
|
506
545
|
requirements: []
|
507
|
-
rubygems_version: 3.
|
546
|
+
rubygems_version: 3.5.22
|
508
547
|
signing_key:
|
509
548
|
specification_version: 4
|
510
549
|
summary: A console-based email client with the best features of GMail, mutt and Emacs
|
@@ -514,7 +553,9 @@ test_files:
|
|
514
553
|
- test/fixtures/binary-content-transfer-encoding-2.eml
|
515
554
|
- test/fixtures/blank-header-fields.eml
|
516
555
|
- test/fixtures/contacts.txt
|
556
|
+
- test/fixtures/embedded-message-rfc6532.eml
|
517
557
|
- test/fixtures/embedded-message.eml
|
558
|
+
- test/fixtures/invalid-date.eml
|
518
559
|
- test/fixtures/mailing-list-header.eml
|
519
560
|
- test/fixtures/malicious-attachment-names.eml
|
520
561
|
- test/fixtures/missing-from-to.eml
|
@@ -531,7 +572,9 @@ test_files:
|
|
531
572
|
- test/fixtures/zimbra-quote-with-bottom-post.eml
|
532
573
|
- test/gnupg_test_home/.gpg-v21-migrated
|
533
574
|
- test/gnupg_test_home/gpg.conf
|
534
|
-
- test/gnupg_test_home/private-keys-v1.d/
|
575
|
+
- test/gnupg_test_home/private-keys-v1.d/26C05E44706A8E230B3255BB9532B34DC9420232.key
|
576
|
+
- test/gnupg_test_home/private-keys-v1.d/D187ADC90EC4DEB7047678EAA37E33A53A465D47.key
|
577
|
+
- test/gnupg_test_home/private-keys-v1.d/FB2D9BD3B1BE90B5BCF697781F8404224B0FCF5B.key
|
535
578
|
- test/gnupg_test_home/pubring.gpg
|
536
579
|
- test/gnupg_test_home/receiver_pubring.gpg
|
537
580
|
- test/gnupg_test_home/receiver_secring.gpg
|
@@ -550,9 +593,11 @@ test_files:
|
|
550
593
|
- test/test_yaml_regressions.rb
|
551
594
|
- test/unit/service/test_label_service.rb
|
552
595
|
- test/unit/test_contact.rb
|
596
|
+
- test/unit/test_edit_message_mode.rb
|
553
597
|
- test/unit/test_horizontal_selector.rb
|
554
598
|
- test/unit/test_locale_fiddler.rb
|
555
599
|
- test/unit/test_person.rb
|
600
|
+
- test/unit/test_rmail_message.rb
|
556
601
|
- test/unit/util/test_query.rb
|
557
602
|
- test/unit/util/test_string.rb
|
558
603
|
- test/unit/util/test_uri.rb
|