sup 1.1 → 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 +40 -38
- data/.gitmodules +1 -0
- data/CONTRIBUTORS +3 -1
- data/History.txt +32 -3
- data/Manifest.txt +34 -1
- data/README.md +0 -1
- data/bin/sup-sync-back-maildir +1 -1
- data/contrib/nix/Gemfile +24 -0
- data/contrib/nix/Gemfile.lock +101 -0
- data/contrib/nix/README +7 -0
- data/contrib/nix/gem-install-shell.nix +14 -0
- data/contrib/nix/gemset.nix +391 -0
- data/contrib/nix/ruby2.4-Gemfile.lock +85 -0
- data/contrib/nix/ruby2.4-gemset.nix +329 -0
- data/contrib/nix/ruby2.4-shell.nix +26 -0
- data/contrib/nix/ruby2.5-Gemfile.lock +85 -0
- data/contrib/nix/ruby2.5-gemset.nix +329 -0
- data/contrib/nix/ruby2.5-shell.nix +26 -0
- data/contrib/nix/ruby2.6-Gemfile.lock +87 -0
- data/contrib/nix/ruby2.6-gemset.nix +339 -0
- data/contrib/nix/ruby2.6-shell.nix +26 -0
- 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 +14 -0
- 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 +14 -0
- data/contrib/nix/ruby3.1-shell.nix +25 -0
- data/contrib/nix/ruby3.2-shell.nix +25 -0
- data/contrib/nix/ruby3.3-shell.nix +25 -0
- data/contrib/nix/ruby3.4-shell.nix +36 -0
- data/contrib/nix/test-all-rubies.sh +6 -0
- data/doc/Hooks.txt +1 -1
- data/ext/mkrf_conf_xapian.rb +2 -2
- data/lib/sup/crypto.rb +8 -6
- data/lib/sup/index.rb +2 -2
- data/lib/sup/maildir.rb +5 -1
- data/lib/sup/mbox.rb +26 -8
- data/lib/sup/message.rb +15 -12
- data/lib/sup/modes/console_mode.rb +1 -1
- data/lib/sup/modes/edit_message_mode.rb +5 -5
- data/lib/sup/thread.rb +20 -20
- data/lib/sup/util.rb +12 -7
- data/lib/sup/version.rb +1 -1
- data/man/sup-add.1 +40 -40
- data/man/sup-config.1 +30 -26
- data/man/sup-dump.1 +38 -38
- data/man/sup-import-dump.1 +41 -37
- data/man/sup-psych-ify-config-files.1 +32 -28
- data/man/sup-recover-sources.1 +39 -35
- data/man/sup-sync-back-maildir.1 +39 -34
- data/man/sup-sync.1 +50 -46
- data/man/sup-tweak-labels.1 +43 -38
- data/man/sup.1 +42 -38
- data/shell.nix +1 -0
- 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 +18 -1
- data/test/integration/test_mbox.rb +13 -0
- data/test/integration/test_sup-sync-back-maildir.rb +40 -0
- data/test/test_crypto.rb +108 -71
- data/test/test_header_parsing.rb +2 -2
- 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 +73 -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_header_parsing.rb
CHANGED
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
|
@@ -322,6 +350,31 @@ files:
|
|
322
350
|
- contrib/colorpicker.rb
|
323
351
|
- contrib/completion/_sup.bash
|
324
352
|
- contrib/completion/_sup.zsh
|
353
|
+
- contrib/nix/Gemfile
|
354
|
+
- contrib/nix/Gemfile.lock
|
355
|
+
- contrib/nix/README
|
356
|
+
- contrib/nix/gem-install-shell.nix
|
357
|
+
- contrib/nix/gemset.nix
|
358
|
+
- contrib/nix/ruby2.4-Gemfile.lock
|
359
|
+
- contrib/nix/ruby2.4-gemset.nix
|
360
|
+
- contrib/nix/ruby2.4-shell.nix
|
361
|
+
- contrib/nix/ruby2.5-Gemfile.lock
|
362
|
+
- contrib/nix/ruby2.5-gemset.nix
|
363
|
+
- contrib/nix/ruby2.5-shell.nix
|
364
|
+
- contrib/nix/ruby2.6-Gemfile.lock
|
365
|
+
- contrib/nix/ruby2.6-gemset.nix
|
366
|
+
- contrib/nix/ruby2.6-shell.nix
|
367
|
+
- contrib/nix/ruby2.7-Gemfile.lock
|
368
|
+
- contrib/nix/ruby2.7-gemset.nix
|
369
|
+
- contrib/nix/ruby2.7-shell.nix
|
370
|
+
- contrib/nix/ruby3.0-Gemfile.lock
|
371
|
+
- contrib/nix/ruby3.0-gemset.nix
|
372
|
+
- contrib/nix/ruby3.0-shell.nix
|
373
|
+
- contrib/nix/ruby3.1-shell.nix
|
374
|
+
- contrib/nix/ruby3.2-shell.nix
|
375
|
+
- contrib/nix/ruby3.3-shell.nix
|
376
|
+
- contrib/nix/ruby3.4-shell.nix
|
377
|
+
- contrib/nix/test-all-rubies.sh
|
325
378
|
- devel/console.sh
|
326
379
|
- devel/count-loc.sh
|
327
380
|
- devel/load-index.rb
|
@@ -408,13 +461,16 @@ files:
|
|
408
461
|
- man/sup-sync.1
|
409
462
|
- man/sup-tweak-labels.1
|
410
463
|
- man/sup.1
|
464
|
+
- shell.nix
|
411
465
|
- sup.gemspec
|
412
466
|
- test/dummy_source.rb
|
413
467
|
- test/fixtures/bad-content-transfer-encoding-1.eml
|
414
468
|
- test/fixtures/binary-content-transfer-encoding-2.eml
|
415
469
|
- test/fixtures/blank-header-fields.eml
|
416
470
|
- test/fixtures/contacts.txt
|
471
|
+
- test/fixtures/embedded-message-rfc6532.eml
|
417
472
|
- test/fixtures/embedded-message.eml
|
473
|
+
- test/fixtures/invalid-date.eml
|
418
474
|
- test/fixtures/mailing-list-header.eml
|
419
475
|
- test/fixtures/malicious-attachment-names.eml
|
420
476
|
- test/fixtures/missing-from-to.eml
|
@@ -431,7 +487,9 @@ files:
|
|
431
487
|
- test/fixtures/zimbra-quote-with-bottom-post.eml
|
432
488
|
- test/gnupg_test_home/.gpg-v21-migrated
|
433
489
|
- test/gnupg_test_home/gpg.conf
|
434
|
-
- 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
|
435
493
|
- test/gnupg_test_home/pubring.gpg
|
436
494
|
- test/gnupg_test_home/receiver_pubring.gpg
|
437
495
|
- test/gnupg_test_home/receiver_secring.gpg
|
@@ -441,6 +499,7 @@ files:
|
|
441
499
|
- test/integration/test_maildir.rb
|
442
500
|
- test/integration/test_mbox.rb
|
443
501
|
- test/integration/test_sup-add.rb
|
502
|
+
- test/integration/test_sup-sync-back-maildir.rb
|
444
503
|
- test/test_crypto.rb
|
445
504
|
- test/test_header_parsing.rb
|
446
505
|
- test/test_helper.rb
|
@@ -449,9 +508,11 @@ files:
|
|
449
508
|
- test/test_yaml_regressions.rb
|
450
509
|
- test/unit/service/test_label_service.rb
|
451
510
|
- test/unit/test_contact.rb
|
511
|
+
- test/unit/test_edit_message_mode.rb
|
452
512
|
- test/unit/test_horizontal_selector.rb
|
453
513
|
- test/unit/test_locale_fiddler.rb
|
454
514
|
- test/unit/test_person.rb
|
515
|
+
- test/unit/test_rmail_message.rb
|
455
516
|
- test/unit/util/test_query.rb
|
456
517
|
- test/unit/util/test_string.rb
|
457
518
|
- test/unit/util/test_uri.rb
|
@@ -482,7 +543,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
482
543
|
- !ruby/object:Gem::Version
|
483
544
|
version: '0'
|
484
545
|
requirements: []
|
485
|
-
rubygems_version: 3.
|
546
|
+
rubygems_version: 3.5.22
|
486
547
|
signing_key:
|
487
548
|
specification_version: 4
|
488
549
|
summary: A console-based email client with the best features of GMail, mutt and Emacs
|
@@ -492,7 +553,9 @@ test_files:
|
|
492
553
|
- test/fixtures/binary-content-transfer-encoding-2.eml
|
493
554
|
- test/fixtures/blank-header-fields.eml
|
494
555
|
- test/fixtures/contacts.txt
|
556
|
+
- test/fixtures/embedded-message-rfc6532.eml
|
495
557
|
- test/fixtures/embedded-message.eml
|
558
|
+
- test/fixtures/invalid-date.eml
|
496
559
|
- test/fixtures/mailing-list-header.eml
|
497
560
|
- test/fixtures/malicious-attachment-names.eml
|
498
561
|
- test/fixtures/missing-from-to.eml
|
@@ -509,7 +572,9 @@ test_files:
|
|
509
572
|
- test/fixtures/zimbra-quote-with-bottom-post.eml
|
510
573
|
- test/gnupg_test_home/.gpg-v21-migrated
|
511
574
|
- test/gnupg_test_home/gpg.conf
|
512
|
-
- 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
|
513
578
|
- test/gnupg_test_home/pubring.gpg
|
514
579
|
- test/gnupg_test_home/receiver_pubring.gpg
|
515
580
|
- test/gnupg_test_home/receiver_secring.gpg
|
@@ -519,6 +584,7 @@ test_files:
|
|
519
584
|
- test/integration/test_maildir.rb
|
520
585
|
- test/integration/test_mbox.rb
|
521
586
|
- test/integration/test_sup-add.rb
|
587
|
+
- test/integration/test_sup-sync-back-maildir.rb
|
522
588
|
- test/test_crypto.rb
|
523
589
|
- test/test_header_parsing.rb
|
524
590
|
- test/test_helper.rb
|
@@ -527,9 +593,11 @@ test_files:
|
|
527
593
|
- test/test_yaml_regressions.rb
|
528
594
|
- test/unit/service/test_label_service.rb
|
529
595
|
- test/unit/test_contact.rb
|
596
|
+
- test/unit/test_edit_message_mode.rb
|
530
597
|
- test/unit/test_horizontal_selector.rb
|
531
598
|
- test/unit/test_locale_fiddler.rb
|
532
599
|
- test/unit/test_person.rb
|
600
|
+
- test/unit/test_rmail_message.rb
|
533
601
|
- test/unit/util/test_query.rb
|
534
602
|
- test/unit/util/test_string.rb
|
535
603
|
- test/unit/util/test_uri.rb
|