mailreport 0.1.0 → 0.1.2
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/CHANGELOG.md +9 -0
- data/README.md +19 -4
- data/lib/mailreport/archive.rb +9 -2
- data/lib/mailreport/dmarc/document.rb +15 -4
- data/lib/mailreport/version.rb +1 -1
- data/mailreport.gemspec +2 -3
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f3d7ccde2b425bc6a1c990efde170016e4ec813c00d3c7ee69c289463f418052
|
|
4
|
+
data.tar.gz: b2e035153e75905c2d13ee5277dd64aac25a7f8bd328f83a7507ee074a457b24
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 65e069ab2aaf56f78be9fcf0553ebefc53e4c68d5831cc6aaa79f609aa7c1e0e4a827c9b612ca8a43af0917954aa65320737021a68edf160e49c7bcf4220d87e
|
|
7
|
+
data.tar.gz: a976676695518993833d4b742907113fa2a57bea2a7c767e2dfff2f43c5073e731475f2e1c2685a7cdd77be65a95497653a99259aa20ee1526af9a312ede1469
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.2
|
|
4
|
+
|
|
5
|
+
- Security: a zip was held to `max_size` by its entries but not by its own size, so an oversized archive was read rather than refused.
|
|
6
|
+
- The default `max_size` drops to 2 MB.
|
|
7
|
+
|
|
8
|
+
## 0.1.1
|
|
9
|
+
|
|
10
|
+
Documentation
|
|
11
|
+
|
|
3
12
|
## 0.1.0
|
|
4
13
|
|
|
5
14
|
Initial release.
|
data/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# mailreport
|
|
2
2
|
|
|
3
|
-
📧
|
|
3
|
+
📧 DMARC report parsing for Ruby.
|
|
4
4
|
|
|
5
|
-
Answers one question:
|
|
5
|
+
Answers one question: how does your mail look on their end?
|
|
6
|
+
|
|
7
|
+
**mailreport** reads the reports receivers send back about your domain.
|
|
6
8
|
|
|
7
9
|
## Features
|
|
8
10
|
|
|
@@ -20,11 +22,14 @@ Answers one question: what are receivers seeing?.
|
|
|
20
22
|
- [What Is Not Filled In](#what-is-not-filled-in)
|
|
21
23
|
- [Unreadable Documents](#unreadable-documents)
|
|
22
24
|
- [Testing](#testing)
|
|
25
|
+
- [History](#history)
|
|
23
26
|
- [Contributing](#contributing)
|
|
24
27
|
- [License](#license)
|
|
25
28
|
|
|
26
29
|
## Getting Started
|
|
27
30
|
|
|
31
|
+
Add this line to your application's Gemfile:
|
|
32
|
+
|
|
28
33
|
```ruby
|
|
29
34
|
gem "mailreport"
|
|
30
35
|
```
|
|
@@ -119,12 +124,13 @@ This is deliberately different from a report carrying no records - that one is a
|
|
|
119
124
|
A `rua` address is published in DNS, so anyone can send anything to it, and the limits assume as much:
|
|
120
125
|
|
|
121
126
|
- **Entity declarations are refused.** A report has none of its own, so the expansion bomb is refused with them. Escapes a real document needs (`&`, `é`) still read.
|
|
122
|
-
- **Decompression stops at
|
|
127
|
+
- **Decompression stops at 2 MB** rather than running to completion.
|
|
123
128
|
|
|
124
129
|
```ruby
|
|
125
130
|
MailReport::Archive.open(bytes, max_size: 1024 * 1024)
|
|
126
131
|
```
|
|
127
132
|
|
|
133
|
+
- **A document of more than 25,000 tags is refused**, however few bytes it spends on them. Tags cost time and memory to read whatever their size, so the count is bounded to 500 records.
|
|
128
134
|
- **External references are never resolved** - no document reads a file, a URL, or a DNS name.
|
|
129
135
|
- **A zip entry is bounded as it inflates**, not on the size it claims.
|
|
130
136
|
|
|
@@ -137,9 +143,18 @@ bundle install
|
|
|
137
143
|
rake
|
|
138
144
|
```
|
|
139
145
|
|
|
146
|
+
## History
|
|
147
|
+
|
|
148
|
+
View the [changelog](CHANGELOG.md).
|
|
149
|
+
|
|
140
150
|
## Contributing
|
|
141
151
|
|
|
142
|
-
|
|
152
|
+
Everyone is encouraged to help improve this project:
|
|
153
|
+
|
|
154
|
+
- [Report bugs](https://github.com/mailpiece/mailreport/issues)
|
|
155
|
+
- Fix bugs and submit pull requests
|
|
156
|
+
- Write, clarify, or fix documentation
|
|
157
|
+
- Suggest or add new features
|
|
143
158
|
|
|
144
159
|
## License
|
|
145
160
|
|
data/lib/mailreport/archive.rb
CHANGED
|
@@ -9,7 +9,9 @@ module MailReport
|
|
|
9
9
|
GZIP = "\x1f\x8b".b
|
|
10
10
|
ZIP = "PK".b
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# Real reports run to KBs; this is headroom, not an expectation - and
|
|
13
|
+
# every byte of it is parse cost a caller may pay before refusing.
|
|
14
|
+
MAX_SIZE = 2 * 1024 * 1024
|
|
13
15
|
CHUNK_SIZE = 64 * 1024
|
|
14
16
|
STORED = 0
|
|
15
17
|
|
|
@@ -23,13 +25,18 @@ module MailReport
|
|
|
23
25
|
def open(bytes, max_size: MAX_SIZE, name: nil)
|
|
24
26
|
bytes = bytes.to_s.b
|
|
25
27
|
|
|
28
|
+
# A real report's container never exceeds what it holds; refuse before
|
|
29
|
+
# reading a zip's central directory, whose entry count (not its bytes)
|
|
30
|
+
# is what costs time to walk.
|
|
26
31
|
if bytes.empty?
|
|
27
32
|
nil
|
|
33
|
+
elsif bytes.bytesize > max_size
|
|
34
|
+
nil
|
|
28
35
|
elsif gzipped?(bytes)
|
|
29
36
|
inflated(bytes, max_size)
|
|
30
37
|
elsif zipped?(bytes)
|
|
31
38
|
unzipped(bytes, max_size, name)
|
|
32
|
-
|
|
39
|
+
else
|
|
33
40
|
bytes
|
|
34
41
|
end
|
|
35
42
|
rescue *UNREADABLE
|
|
@@ -10,8 +10,11 @@ module MailReport
|
|
|
10
10
|
|
|
11
11
|
PREDEFINED_ENTITIES = %w[ lt gt amp quot apos ].freeze
|
|
12
12
|
|
|
13
|
-
#
|
|
14
|
-
#
|
|
13
|
+
# A tag costs time and memory to build however few bytes it spends, so
|
|
14
|
+
# the count is bounded as well as the size. Room for some 500 records
|
|
15
|
+
MAX_TAGS = 25_000
|
|
16
|
+
|
|
17
|
+
# REXML raises a bare RuntimeError when expansion limits trip
|
|
15
18
|
EXPANSION_ABANDONED = /entity expansions exceeded|entity expansion has grown too large/
|
|
16
19
|
|
|
17
20
|
def initialize(xml)
|
|
@@ -34,9 +37,17 @@ module MailReport
|
|
|
34
37
|
|
|
35
38
|
private
|
|
36
39
|
def feedback
|
|
37
|
-
|
|
40
|
+
if countable?
|
|
41
|
+
document = REXML::Document.new(@xml)
|
|
42
|
+
|
|
43
|
+
document.root if readable?(document) && document.root&.name == ROOT
|
|
44
|
+
end
|
|
45
|
+
end
|
|
38
46
|
|
|
39
|
-
|
|
47
|
+
# Every tag opens with one, so this over-counts where text or a comment
|
|
48
|
+
# holds a `<` — which refuses in the direction we want.
|
|
49
|
+
def countable?
|
|
50
|
+
@xml.to_s.count("<") <= MAX_TAGS
|
|
40
51
|
end
|
|
41
52
|
|
|
42
53
|
# Refuse any declared entity before text is read (expansion timing).
|
data/lib/mailreport/version.rb
CHANGED
data/mailreport.gemspec
CHANGED
|
@@ -7,10 +7,9 @@ Gem::Specification.new do |spec|
|
|
|
7
7
|
spec.platform = Gem::Platform::RUBY
|
|
8
8
|
spec.required_ruby_version = ">= 3.3.4"
|
|
9
9
|
spec.authors = [ "Simon Lev" ]
|
|
10
|
-
spec.email = [ "support@postrider.dev" ]
|
|
11
10
|
|
|
12
|
-
spec.summary = "DMARC
|
|
13
|
-
spec.description = "Answers one question about your domain
|
|
11
|
+
spec.summary = "DMARC report parsing for Ruby."
|
|
12
|
+
spec.description = "Answers one question: how does your mail look on their end? Reads the reports receivers send back about your domain. Parses DMARC aggregate (RUA) and failure (RUF) reports."
|
|
14
13
|
|
|
15
14
|
spec.homepage = "https://github.com/mailpiece/mailreport"
|
|
16
15
|
spec.license = "MIT"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mailreport
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Simon Lev
|
|
@@ -37,9 +37,9 @@ dependencies:
|
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '6.3'
|
|
40
|
-
description: 'Answers one question
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
description: 'Answers one question: how does your mail look on their end? Reads the
|
|
41
|
+
reports receivers send back about your domain. Parses DMARC aggregate (RUA) and
|
|
42
|
+
failure (RUF) reports.'
|
|
43
43
|
executables: []
|
|
44
44
|
extensions: []
|
|
45
45
|
extra_rdoc_files: []
|
|
@@ -79,5 +79,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
79
79
|
requirements: []
|
|
80
80
|
rubygems_version: 4.0.3
|
|
81
81
|
specification_version: 4
|
|
82
|
-
summary: DMARC
|
|
82
|
+
summary: DMARC report parsing for Ruby.
|
|
83
83
|
test_files: []
|