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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4144dc7ef1d3210db021841accb097def4cf61d4edd582064920f994da16a262
4
- data.tar.gz: cdeffe809666d65141cbbc169d110eadb3be17a30bfaf6311b5382af0ddd69ee
3
+ metadata.gz: f3d7ccde2b425bc6a1c990efde170016e4ec813c00d3c7ee69c289463f418052
4
+ data.tar.gz: b2e035153e75905c2d13ee5277dd64aac25a7f8bd328f83a7507ee074a457b24
5
5
  SHA512:
6
- metadata.gz: fe3ab048394c0dd88eb5d8ff99f1a0be42eff511c2add007753e39423e75d01d156a6815b07853a78469c8e7e839e01ffc265b404648a542494e21799b14f092
7
- data.tar.gz: 8d59fb0ec330e5e5099ebeac2bd15420b9f53257a1a0f5ebb3b6c420de653ffcf26577396093f87aec4c86a26102ae1b4696a91824de7e7489addb9a1dc8cf62
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
- 📧 Read the reports receivers send back about your domain
3
+ 📧 DMARC report parsing for Ruby.
4
4
 
5
- Answers one question: what are receivers seeing?.
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 25 MB** rather than running to completion. Lower it where you'd rather hold less:
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
- See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports: [GitHub issues](https://github.com/mailpiece/mailreport/issues). Security: [SECURITY.md](SECURITY.md).
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
 
@@ -9,7 +9,9 @@ module MailReport
9
9
  GZIP = "\x1f\x8b".b
10
10
  ZIP = "PK".b
11
11
 
12
- MAX_SIZE = 25 * 1024 * 1024
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
- elsif bytes.bytesize <= max_size
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
- # REXML raises a bare RuntimeError when expansion limits trip; match the
14
- # message so our own RuntimeErrors are not swallowed as unreadable input.
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
- document = REXML::Document.new(@xml)
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
- document.root if readable?(document) && document.root&.name == ROOT
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).
@@ -1,3 +1,3 @@
1
1
  module MailReport
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.2"
3
3
  end
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 aggregate and SMTP TLS reports, parsed in pure Ruby."
13
- spec.description = "Answers one question about your domain: what are receivers seeing?"
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.0
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 about your domain: what are receivers seeing?'
41
- email:
42
- - support@postrider.dev
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 aggregate and SMTP TLS reports, parsed in pure Ruby.
82
+ summary: DMARC report parsing for Ruby.
83
83
  test_files: []