Class: MtaSts::Policy

Inherits:
Object
  • Object
show all
Defined in:
lib/mta_sts/policy.rb

Defined Under Namespace

Classes: Invalid

Constant Summary collapse

POLICY_VERSION =
"STSv1"
MODES =
%i[ none testing enforce ].freeze
MAX_AGE =

RFC 8461 §3.2

(0..31_557_600)
WILDCARD =
"*."
TERMINATOR =

RFC 8461 §3.2 ABNF: sts-policy-term = LF / CRLF

/\r?\n/
DIGITS =
/\A\d+\z/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mode:, max_age:, mx: [], id: nil, domain: nil, fetched_at: Time.now) ⇒ Policy

Returns a new instance of Policy.



84
85
86
87
88
89
90
# File 'lib/mta_sts/policy.rb', line 84

def initialize(mode:, max_age:, mx: [], id: nil, domain: nil, fetched_at: Time.now)
  @mode = validated_mode(mode)
  @mx = validated_mx(mx)
  @max_age = validated_max_age(max_age)
  @domain = domain && self.class.normalize(domain)
  @id, @fetched_at = id, fetched_at
end

Instance Attribute Details

#domainObject (readonly)

Returns the value of attribute domain.



82
83
84
# File 'lib/mta_sts/policy.rb', line 82

def domain
  @domain
end

#fetched_atObject (readonly)

Returns the value of attribute fetched_at.



82
83
84
# File 'lib/mta_sts/policy.rb', line 82

def fetched_at
  @fetched_at
end

#idObject (readonly)

Returns the value of attribute id.



82
83
84
# File 'lib/mta_sts/policy.rb', line 82

def id
  @id
end

#max_ageObject (readonly)

Returns the value of attribute max_age.



82
83
84
# File 'lib/mta_sts/policy.rb', line 82

def max_age
  @max_age
end

#modeObject (readonly)

Returns the value of attribute mode.



82
83
84
# File 'lib/mta_sts/policy.rb', line 82

def mode
  @mode
end

#mxObject (readonly)

Returns the value of attribute mx.



82
83
84
# File 'lib/mta_sts/policy.rb', line 82

def mx
  @mx
end

Class Method Details

.normalize(name) ⇒ Object



24
25
26
27
28
29
30
31
32
# File 'lib/mta_sts/policy.rb', line 24

def normalize(name)
  name = scrubbed(name).strip.chomp(".")

  if name.start_with?(WILDCARD)
    WILDCARD + ascii(name.delete_prefix(WILDCARD)).downcase
  else
    ascii(name).downcase
  end
end

.parse(text, id: nil, domain: nil, fetched_at: Time.now) ⇒ Object



15
16
17
18
19
20
21
22
# File 'lib/mta_sts/policy.rb', line 15

def parse(text, id: nil, domain: nil, fetched_at: Time.now)
  fields = fields_in(text)

  validate_version single(fields, "version")

  new mode: single(fields, "mode"), mx: fields.fetch("mx", []), max_age: single(fields, "max_age"),
    id: id, domain: domain, fetched_at: fetched_at
end

Instance Method Details

#allows?(host) ⇒ Boolean

Returns:

  • (Boolean)


104
105
106
107
108
109
110
111
112
# File 'lib/mta_sts/policy.rb', line 104

def allows?(host)
  if none?
    true
  else
    host = self.class.normalize(host)

    mx.any? { |pattern| matches?(pattern, host) }
  end
end

#enforce?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/mta_sts/policy.rb', line 100

def enforce?
  mode == :enforce
end

#expired?(now = Time.now) ⇒ Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/mta_sts/policy.rb', line 118

def expired?(now = Time.now)
  now >= expires_at
end

#expires_atObject



114
115
116
# File 'lib/mta_sts/policy.rb', line 114

def expires_at
  fetched_at + max_age
end

#inspectObject



130
131
132
# File 'lib/mta_sts/policy.rb', line 130

def inspect
  "#<#{self.class.name} mode: #{mode.inspect}, mx: #{mx.inspect}, max_age: #{max_age.inspect}>"
end

#none?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/mta_sts/policy.rb', line 92

def none?
  mode == :none
end

#testing?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/mta_sts/policy.rb', line 96

def testing?
  mode == :testing
end

#to_sObject



122
123
124
125
126
127
128
# File 'lib/mta_sts/policy.rb', line 122

def to_s
  lines = [ "version: #{POLICY_VERSION}", "mode: #{mode}" ]
  lines.concat mx.map { |pattern| "mx: #{pattern}" }
  lines << "max_age: #{max_age}"

  lines.map { |line| "#{line}\r\n" }.join
end