dmarcator 0.1.0 → 0.3.0

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.
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'dmarcator/report'
5
+ require 'bigdecimal'
6
+
7
+ RSpec.describe DMARCator::Report do
8
+ let(:example_path) { File.join(__dir__, 'support', 'complete.xml') }
9
+ let(:google_path) { File.join(__dir__, 'support', 'google.xml') }
10
+
11
+ let(:xml_report) { File.read(example_path) }
12
+ let(:google_report) { File.read(google_path) }
13
+
14
+ it 'has a version number' do
15
+ expect(DMARCator::VERSION).not_to be_nil
16
+ end
17
+
18
+ it 'reads report version if available' do
19
+ report = described_class.new(xml_report)
20
+ expect(report.version).to eq(BigDecimal('0.1'))
21
+
22
+ google = described_class.new(google_report)
23
+ expect(google.version).to be_nil
24
+ end
25
+
26
+ it 'returns nil for a non-numeric report version' do
27
+ report = described_class.new('<feedback><version>abc</version></feedback>')
28
+
29
+ expect(report.version).to be_nil
30
+ end
31
+
32
+ it 'raises InvalidReport for malformed XML' do
33
+ expect {
34
+ described_class.new('this is not xml')
35
+ }.to raise_error(DMARCator::InvalidReport)
36
+ end
37
+
38
+ it 'returns nil for a non-numeric timestamp' do
39
+ report = described_class.new(
40
+ '<feedback><report_metadata><date_range><begin>notanumber</begin></date_range></report_metadata></feedback>'
41
+ )
42
+
43
+ expect(report.metadata.begin_at).to be_nil
44
+ end
45
+
46
+ it 'parses timestamps with surrounding whitespace' do
47
+ report = described_class.new(
48
+ '<feedback><report_metadata><date_range><begin> 1593648000 </begin></date_range></report_metadata></feedback>'
49
+ )
50
+
51
+ expect(report.metadata.begin_at).to eq(Time.at(1_593_648_000))
52
+ end
53
+
54
+ it 'reads report metadata' do
55
+ report = described_class.new(xml_report)
56
+
57
+ expect(report.metadata.org_name).to eq('google.com')
58
+ expect(report.metadata.email).to eq('noreply-dmarc-support@google.com')
59
+ expect(report.metadata.extra_contact_info).to eq('https://support.google.com/a/answer/2466580')
60
+ expect(report.metadata.report_id).to eq('3114726731964606297')
61
+ expect(report.metadata.begin_at).to eq(Time.at(1_593_648_000))
62
+ expect(report.metadata.end_at).to eq(Time.at(1_593_734_399))
63
+ expect(report.metadata.errors).to eq(['some error', 'another error'])
64
+ end
65
+
66
+ it 'reads policy published' do
67
+ report = described_class.new(xml_report)
68
+
69
+ expect(report.policy.domain).to eq('opserv.io')
70
+ expect(report.policy.adkim).to eq('r')
71
+ expect(report.policy.aspf).to eq('r')
72
+ expect(report.policy.p).to eq('none')
73
+ expect(report.policy.sp).to eq('none')
74
+ expect(report.policy.pct).to eq(100)
75
+ expect(report.policy.fo).to eq('1')
76
+ end
77
+
78
+ it 'reads report records' do
79
+ report = described_class.new(xml_report)
80
+ record = report.records.first
81
+
82
+ expect(record.source_ip).to eq('209.85.220.69')
83
+ expect(record.count).to eq(96)
84
+ expect(record.disposition).to eq('none')
85
+ expect(record.dkim).to eq('fail')
86
+ expect(record.spf).to eq('fail')
87
+
88
+ expect(record.reasons.count).to eq(2)
89
+ expect(record.reasons.first.type).to eq('local_policy')
90
+ expect(record.reasons.first.comment).to eq('arc=pass')
91
+ expect(record.reasons.last.type).to eq('other')
92
+ expect(record.reasons.last.comment).to eq('dkim=pass')
93
+
94
+ expect(record.envelope_to).to eq('envelope-to.io')
95
+ expect(record.envelope_from).to eq('envelope-from.io')
96
+ expect(record.header_from).to eq('opserv.io')
97
+
98
+ expect(record.auth_results.count).to eq(2)
99
+ expect(record.auth_results.first.type).to eq('dkim')
100
+ expect(record.auth_results.first.domain).to eq('condenast-com-tw.20150623.gappssmtp.com')
101
+ expect(record.auth_results.first.result).to eq('pass')
102
+ expect(record.auth_results.first.selector).to eq('20150623')
103
+ expect(record.auth_results.last.type).to eq('spf')
104
+ expect(record.auth_results.last.domain).to eq('condenast.com.tw')
105
+ expect(record.auth_results.last.result).to eq('neutral')
106
+ expect(record.auth_results.last.scope).to eq('mfrom')
107
+ end
108
+ end
@@ -0,0 +1,364 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <feedback xmlns="urn:ietf:params:xml:ns:dmarc-2.0">
3
+ <version>0.1</version>
4
+ <report_metadata>
5
+ <org_name>google.com</org_name>
6
+ <email>noreply-dmarc-support@google.com</email>
7
+ <extra_contact_info>https://support.google.com/a/answer/2466580</extra_contact_info>
8
+ <report_id>3114726731964606297</report_id>
9
+ <date_range>
10
+ <begin>1593648000</begin>
11
+ <end>1593734399</end>
12
+ </date_range>
13
+ <error>some error</error>
14
+ <error>another error</error>
15
+ </report_metadata>
16
+ <policy_published>
17
+ <domain>opserv.io</domain>
18
+ <adkim>r</adkim>
19
+ <aspf>r</aspf>
20
+ <p>none</p>
21
+ <sp>none</sp>
22
+ <pct>100</pct>
23
+ <fo>1</fo>
24
+ </policy_published>
25
+ <record>
26
+ <row>
27
+ <source_ip>209.85.220.69</source_ip>
28
+ <count>96</count>
29
+ <policy_evaluated>
30
+ <disposition>none</disposition>
31
+ <dkim>fail</dkim>
32
+ <spf>fail</spf>
33
+ <reason>
34
+ <type>local_policy</type>
35
+ <comment>arc=pass</comment>
36
+ </reason>
37
+ <reason>
38
+ <type>other</type>
39
+ <comment>dkim=pass</comment>
40
+ </reason>
41
+ </policy_evaluated>
42
+ </row>
43
+ <identifiers>
44
+ <envelope_to>envelope-to.io</envelope_to>
45
+ <envelope_from>envelope-from.io</envelope_from>
46
+ <header_from>opserv.io</header_from>
47
+ </identifiers>
48
+ <auth_results>
49
+ <dkim>
50
+ <domain>condenast-com-tw.20150623.gappssmtp.com</domain>
51
+ <result>pass</result>
52
+ <selector>20150623</selector>
53
+ </dkim>
54
+ <spf>
55
+ <domain>condenast.com.tw</domain>
56
+ <result>neutral</result>
57
+ <scope>mfrom</scope>
58
+ </spf>
59
+ </auth_results>
60
+ </record>
61
+ <record>
62
+ <row>
63
+ <source_ip>167.89.100.132</source_ip>
64
+ <count>11</count>
65
+ <policy_evaluated>
66
+ <disposition>none</disposition>
67
+ <dkim>pass</dkim>
68
+ <spf>pass</spf>
69
+ </policy_evaluated>
70
+ </row>
71
+ <identifiers>
72
+ <header_from>opserv.io</header_from>
73
+ </identifiers>
74
+ <auth_results>
75
+ <dkim>
76
+ <domain>opserv.io</domain>
77
+ <result>pass</result>
78
+ <selector>s1</selector>
79
+ </dkim>
80
+ <dkim>
81
+ <domain>sendgrid.info</domain>
82
+ <result>pass</result>
83
+ <selector>smtpapi</selector>
84
+ </dkim>
85
+ <spf>
86
+ <domain>alert.opserv.io</domain>
87
+ <result>pass</result>
88
+ </spf>
89
+ </auth_results>
90
+ </record>
91
+ <record>
92
+ <row>
93
+ <source_ip>167.89.100.13</source_ip>
94
+ <count>96</count>
95
+ <policy_evaluated>
96
+ <disposition>none</disposition>
97
+ <dkim>pass</dkim>
98
+ <spf>pass</spf>
99
+ </policy_evaluated>
100
+ </row>
101
+ <identifiers>
102
+ <header_from>opserv.io</header_from>
103
+ </identifiers>
104
+ <auth_results>
105
+ <dkim>
106
+ <domain>opserv.io</domain>
107
+ <result>pass</result>
108
+ <selector>s1</selector>
109
+ </dkim>
110
+ <dkim>
111
+ <domain>sendgrid.info</domain>
112
+ <result>pass</result>
113
+ <selector>smtpapi</selector>
114
+ </dkim>
115
+ <spf>
116
+ <domain>alert.opserv.io</domain>
117
+ <result>pass</result>
118
+ </spf>
119
+ </auth_results>
120
+ </record>
121
+ <record>
122
+ <row>
123
+ <source_ip>167.89.100.13</source_ip>
124
+ <count>161</count>
125
+ <policy_evaluated>
126
+ <disposition>none</disposition>
127
+ <dkim>pass</dkim>
128
+ <spf>pass</spf>
129
+ </policy_evaluated>
130
+ </row>
131
+ <identifiers>
132
+ <header_from>opserv.io</header_from>
133
+ </identifiers>
134
+ <auth_results>
135
+ <dkim>
136
+ <domain>opserv.io</domain>
137
+ <result>pass</result>
138
+ <selector>s1</selector>
139
+ </dkim>
140
+ <spf>
141
+ <domain>alert.opserv.io</domain>
142
+ <result>pass</result>
143
+ </spf>
144
+ </auth_results>
145
+ </record>
146
+ <record>
147
+ <row>
148
+ <source_ip>50.31.60.236</source_ip>
149
+ <count>28</count>
150
+ <policy_evaluated>
151
+ <disposition>none</disposition>
152
+ <dkim>pass</dkim>
153
+ <spf>pass</spf>
154
+ </policy_evaluated>
155
+ </row>
156
+ <identifiers>
157
+ <header_from>opserv.io</header_from>
158
+ </identifiers>
159
+ <auth_results>
160
+ <dkim>
161
+ <domain>opserv.io</domain>
162
+ <result>pass</result>
163
+ <selector>s1</selector>
164
+ </dkim>
165
+ <spf>
166
+ <domain>alert.opserv.io</domain>
167
+ <result>pass</result>
168
+ </spf>
169
+ </auth_results>
170
+ </record>
171
+ <record>
172
+ <row>
173
+ <source_ip>50.31.60.236</source_ip>
174
+ <count>13</count>
175
+ <policy_evaluated>
176
+ <disposition>none</disposition>
177
+ <dkim>pass</dkim>
178
+ <spf>pass</spf>
179
+ </policy_evaluated>
180
+ </row>
181
+ <identifiers>
182
+ <header_from>opserv.io</header_from>
183
+ </identifiers>
184
+ <auth_results>
185
+ <dkim>
186
+ <domain>opserv.io</domain>
187
+ <result>pass</result>
188
+ <selector>s1</selector>
189
+ </dkim>
190
+ <dkim>
191
+ <domain>sendgrid.info</domain>
192
+ <result>pass</result>
193
+ <selector>smtpapi</selector>
194
+ </dkim>
195
+ <spf>
196
+ <domain>alert.opserv.io</domain>
197
+ <result>pass</result>
198
+ </spf>
199
+ </auth_results>
200
+ </record>
201
+ <record>
202
+ <row>
203
+ <source_ip>209.85.220.41</source_ip>
204
+ <count>3</count>
205
+ <policy_evaluated>
206
+ <disposition>none</disposition>
207
+ <dkim>pass</dkim>
208
+ <spf>fail</spf>
209
+ </policy_evaluated>
210
+ </row>
211
+ <identifiers>
212
+ <header_from>opserv.io</header_from>
213
+ </identifiers>
214
+ <auth_results>
215
+ <dkim>
216
+ <domain>opserv.io</domain>
217
+ <result>pass</result>
218
+ <selector>s1</selector>
219
+ </dkim>
220
+ <spf>
221
+ <domain>hta.gr</domain>
222
+ <result>pass</result>
223
+ </spf>
224
+ </auth_results>
225
+ </record>
226
+ <record>
227
+ <row>
228
+ <source_ip>209.85.220.69</source_ip>
229
+ <count>10</count>
230
+ <policy_evaluated>
231
+ <disposition>none</disposition>
232
+ <dkim>fail</dkim>
233
+ <spf>fail</spf>
234
+ <reason>
235
+ <type>local_policy</type>
236
+ <comment>arc=pass</comment>
237
+ </reason>
238
+ </policy_evaluated>
239
+ </row>
240
+ <identifiers>
241
+ <header_from>opserv.io</header_from>
242
+ </identifiers>
243
+ <auth_results>
244
+ <dkim>
245
+ <domain>unicstay-com.20150623.gappssmtp.com</domain>
246
+ <result>pass</result>
247
+ <selector>20150623</selector>
248
+ </dkim>
249
+ <spf>
250
+ <domain>unicstay.com</domain>
251
+ <result>pass</result>
252
+ </spf>
253
+ </auth_results>
254
+ </record>
255
+ <record>
256
+ <row>
257
+ <source_ip>209.85.220.41</source_ip>
258
+ <count>3</count>
259
+ <policy_evaluated>
260
+ <disposition>none</disposition>
261
+ <dkim>pass</dkim>
262
+ <spf>fail</spf>
263
+ </policy_evaluated>
264
+ </row>
265
+ <identifiers>
266
+ <header_from>opserv.io</header_from>
267
+ </identifiers>
268
+ <auth_results>
269
+ <dkim>
270
+ <domain>opserv.io</domain>
271
+ <result>pass</result>
272
+ <selector>s1</selector>
273
+ </dkim>
274
+ <dkim>
275
+ <domain>sendgrid.info</domain>
276
+ <result>pass</result>
277
+ <selector>smtpapi</selector>
278
+ </dkim>
279
+ <spf>
280
+ <domain>gmail.com</domain>
281
+ <result>pass</result>
282
+ </spf>
283
+ </auth_results>
284
+ </record>
285
+ <record>
286
+ <row>
287
+ <source_ip>167.89.100.132</source_ip>
288
+ <count>31</count>
289
+ <policy_evaluated>
290
+ <disposition>none</disposition>
291
+ <dkim>pass</dkim>
292
+ <spf>pass</spf>
293
+ </policy_evaluated>
294
+ </row>
295
+ <identifiers>
296
+ <header_from>opserv.io</header_from>
297
+ </identifiers>
298
+ <auth_results>
299
+ <dkim>
300
+ <domain>opserv.io</domain>
301
+ <result>pass</result>
302
+ <selector>s1</selector>
303
+ </dkim>
304
+ <spf>
305
+ <domain>alert.opserv.io</domain>
306
+ <result>pass</result>
307
+ </spf>
308
+ </auth_results>
309
+ </record>
310
+ <record>
311
+ <row>
312
+ <source_ip>209.85.220.69</source_ip>
313
+ <count>6</count>
314
+ <policy_evaluated>
315
+ <disposition>none</disposition>
316
+ <dkim>fail</dkim>
317
+ <spf>fail</spf>
318
+ <reason>
319
+ <type>local_policy</type>
320
+ <comment>arc=pass</comment>
321
+ </reason>
322
+ </policy_evaluated>
323
+ </row>
324
+ <identifiers>
325
+ <header_from>opserv.io</header_from>
326
+ </identifiers>
327
+ <auth_results>
328
+ <dkim>
329
+ <domain>sportskeeda.com</domain>
330
+ <result>pass</result>
331
+ <selector>google</selector>
332
+ </dkim>
333
+ <spf>
334
+ <domain>sportskeeda.com</domain>
335
+ <result>pass</result>
336
+ </spf>
337
+ </auth_results>
338
+ </record>
339
+ <record>
340
+ <row>
341
+ <source_ip>209.85.220.41</source_ip>
342
+ <count>66</count>
343
+ <policy_evaluated>
344
+ <disposition>none</disposition>
345
+ <dkim>pass</dkim>
346
+ <spf>fail</spf>
347
+ </policy_evaluated>
348
+ </row>
349
+ <identifiers>
350
+ <header_from>opserv.io</header_from>
351
+ </identifiers>
352
+ <auth_results>
353
+ <dkim>
354
+ <domain>opserv.io</domain>
355
+ <result>pass</result>
356
+ <selector>s1</selector>
357
+ </dkim>
358
+ <spf>
359
+ <domain>mmprojects.co.uk</domain>
360
+ <result>pass</result>
361
+ </spf>
362
+ </auth_results>
363
+ </record>
364
+ </feedback>