Class: MailAuth::Spf::Record
- Inherits:
-
Object
- Object
- MailAuth::Spf::Record
- Defined in:
- lib/mailauth/spf/record.rb
Overview
A v=spf1 record, read and taken apart. Parsing is complete before
evaluation begins, so v=spf1 -all ip6 is a broken record — not a fail
— even though nothing after -all can ever be evaluated.
Constant Summary collapse
- VERSION =
"v=spf1"- MODIFIER =
A modifier is a name and an "=" reached before any ":" or "/".
redirect:example.comtherefore isn't one — it's a mechanism named "redirect", which is to say a typo. The name stops at the first "=": every one after it belongs to the macro-string, where "=" is both a legal delimiter and a legal literal. /\A(?<name>[^:\/=]*)=(?<value>.*)\z/- MODIFIER_NAME =
/\A[a-z][a-z0-9\-_.]*\z/i- MECHANISM =
/\A(?<qualifier>[+\-~?])?(?<name>[a-z0-9_.\-]+)(?<argument>[:\/].*)?\z/i- ARGUMENT =
domain-spec followed by an optional dual-cidr-length. The domain is matched lazily so that a trailing "/24" is read as a prefix length, while the slashes a domain-spec is allowed to contain stay in the name.
/\A(?<spec>.*?)(?:\/(?<cidr4>\d+))?(?:\/\/(?<cidr6>\d+))?\z/- DUAL_CIDR =
/\A(?:\/(?<cidr4>\d+))?(?:\/\/(?<cidr6>\d+))?\z/- ADDRESS =
/\A(?<address>.*?)(?:\/(?<length>\d+))?\z/- PRINTABLE =
SPF is defined over 7-bit ASCII, and a record carrying anything else has been mangled somewhere between its author and us.
/\A[\x20-\x7e]*\z/
Instance Attribute Summary collapse
-
#redirect ⇒ Object
readonly
Returns the value of attribute redirect.
-
#terms ⇒ Object
readonly
Returns the value of attribute terms.
Class Method Summary collapse
-
.fetch(domain, budget:, context:) ⇒ Object
Zero is not an error but an answer — the domain publishes no policy.
Instance Method Summary collapse
-
#initialize(text, context) ⇒ Record
constructor
A new instance of Record.
Constructor Details
#initialize(text, context) ⇒ Record
Returns a new instance of Record.
52 53 54 55 56 57 58 59 |
# File 'lib/mailauth/spf/record.rb', line 52 def initialize(text, context) @text = text @context = context @terms = [] @modifiers = {} parse end |
Instance Attribute Details
#redirect ⇒ Object (readonly)
Returns the value of attribute redirect.
50 51 52 |
# File 'lib/mailauth/spf/record.rb', line 50 def redirect @redirect end |
#terms ⇒ Object (readonly)
Returns the value of attribute terms.
50 51 52 |
# File 'lib/mailauth/spf/record.rb', line 50 def terms @terms end |
Class Method Details
.fetch(domain, budget:, context:) ⇒ Object
Zero is not an error but an answer — the domain publishes no policy. Two is: nothing chooses between them.
40 41 42 43 44 45 46 47 48 |
# File 'lib/mailauth/spf/record.rb', line 40 def self.fetch(domain, budget:, context:) records = budget.txt(domain).select { |record| record.strip.split(/\s+/).first&.downcase == VERSION } case records.length when 0 then raise NoRecord, "no SPF record for #{domain}" when 1 then new(records.first, context) else raise PermError, "#{records.length} SPF records for #{domain}" end end |