~ar-python-hackers/authentication-results-python/trunk

« back to all changes in this revision

Viewing changes to authres/core.py

  • Committer: Scott Kitterman
  • Date: 2018-10-30 03:44:32 UTC
  • Revision ID: scott@kitterman.com-20181030034432-mtoe0qvj31wavzjf
Tags: 1.1.1
--- 1.1.1 2018-10-30
  + Added ARC specific tags for draft-ietf-dmarc-arc-protocol-18 (as of IETF
    last call, still experimental), smtp.remote-ip and header.oldest-pass

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# coding: utf-8
2
2
 
3
3
# Copyright © 2011-2013 Julian Mehnle <julian@mehnle.net>,
4
 
# Copyright © 2011-2013 Scott Kitterman <scott@kitterman.com>
 
4
# Copyright © 2011-2018 Scott Kitterman <scott@kitterman.com>
5
5
#
6
6
# Licensed under the Apache License, Version 2.0 (the "License");
7
7
# you may not use this file except in compliance with the License.
241
241
        reason               = None,  reason_comment               = None,
242
242
        properties = None,
243
243
        header_d             = None,  header_d_comment             = None,
244
 
        header_i             = None,  header_i_comment             = None
 
244
        header_i             = None,  header_i_comment             = None,
 
245
        header_a             = None,  header_a_comment             = None,
 
246
        header_s             = None,  header_s_comment             = None
245
247
    ):
246
248
        AuthenticationResult.__init__(self, self.METHOD, version,
247
249
            result, result_comment, reason, reason_comment, properties)
249
251
        if header_d_comment:             self.header_d_comment             = header_d_comment
250
252
        if header_i:                     self.header_i                     = header_i
251
253
        if header_i_comment:             self.header_i_comment             = header_i_comment
 
254
        if header_a:                     self.header_a                     = header_a
 
255
        if header_a_comment:             self.header_a_comment             = header_a_comment
 
256
        if header_s:                     self.header_s                     = header_s
 
257
        if header_s_comment:             self.header_s_comment             = header_s_comment
252
258
 
253
259
    header_d,             header_d_comment             = make_result_class_properties('header', 'd')
254
260
    header_i,             header_i_comment             = make_result_class_properties('header', 'i')
 
261
    header_a,             header_a_comment             = make_result_class_properties('header', 'a')
 
262
    header_s,             header_s_comment             = make_result_class_properties('header', 's')
255
263
 
256
264
    def match_signature(self, signature_d):
257
265
        """Match authentication result against a DKIM signature by ``header.d``."""
258
266
 
259
267
        return self.header_d == signature_d
260
268
 
 
269
    def match_signature_algorithm(self, signature_d, signature_a):
 
270
        """Match authentication result against a DKIM signature by ``header.d`` and ``header.a``."""
 
271
 
 
272
        return self.header_d == signature_d and self.header_a == signature_a
 
273
 
261
274
class DomainKeysAuthenticationResult(AuthenticationResult):
262
275
    "DomainKeys result clause of an ``Authentication-Results`` header"
263
276
 
445
458
        feature_context,
446
459
        authserv_id = None,  authserv_id_comment = None,
447
460
        version     = None,  version_comment     = None,
448
 
        results     = None
 
461
        results     = None,  strict              = False
449
462
    ):
450
463
        self.feature_context     = feature_context
451
464
        self.authserv_id         = authserv_id and authserv_id.lower()
457
470
        if self.version_comment and not self.version:
458
471
            raise OrphanCommentError('Cannot include header version comment without associated header version')
459
472
        self.results             = results or []
 
473
        self.strict              = strict # TODO Figure out how to set this programatically
460
474
 
461
475
    def __str__(self):
462
476
        return ''.join((self.HEADER_FIELD_NAME, ': ', self.header_value()))
539
553
            properties = []
540
554
            property_ = True
541
555
            while property_:
542
 
                self._parse_rfc5322_cfws()
543
 
                property_ = self._parse_propspec()
544
 
                if property_:
545
 
                    properties.append(property_)
 
556
                try:
 
557
                    self._parse_rfc5322_cfws()
 
558
                    property_ = self._parse_propspec()
 
559
                    if property_:
 
560
                        properties.append(property_)
 
561
                except:
 
562
                    if self.strict:
 
563
                        raise
 
564
                    else:
 
565
                        pass
546
566
            return self.feature_context.result(method, version, result, None, reason, None, properties)
547
567
 
548
568
    def _parse_methodspec(self):
586
606
        if not ptype:
587
607
            return
588
608
        elif ptype.lower() not in ['smtp', 'header', 'body', 'policy']:
589
 
            raise SyntaxError('Invalid ptype; expected any of "smtp", "header", "body", "policy", got "%s"' % ptype, self._parse_text)
 
609
            self._parse_rfc5322_cfws()
 
610
            self._parse_pattern(r'\.')
 
611
            self._parse_rfc5322_cfws()
 
612
            self._parse_dot_key_atom()
 
613
            self._parse_pattern(r'=')
 
614
            self._parse_pvalue()
 
615
            raise SyntaxError('Invalid ptype; expected any of "smtp", "header", "body", "policy", got "{0}"'.format(ptype))
590
616
        self._parse_rfc5322_cfws()
591
617
        if not self._parse_pattern(r'\.'):
592
618
            raise SyntaxError('Expected "."', self._parse_text)