aboutsummaryrefslogtreecommitdiff
path: root/lib/mauve/configuration.rb
blob: 8a2ed744df87f0e73ba5512c2fc750a7d82b690e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
require 'mauve/source_list'
require 'mauve/people_list'
require 'mauve/mauve_time'

module Mauve

  # Configuration object for Mauve.  This is used as the context in
  # Mauve::ConfigurationBuilder.
  #
  class Configuration

    class << self
      # The current configuration
      # @param  [Mauve::Configuration]
      # @return [Mauve::Configuration]
      attr_accessor :current
    end

    # The Server instance
    # @return [Mauve::Server]
    attr_accessor :server

    # Notification methods
    # @return [Hash]
    attr_reader   :notification_methods

    # People
    # @return [Hash]
    attr_reader   :people

    # Alert groups
    # @return [Array]
    attr_reader   :alert_groups

    # The source lists
    # @return [Hash]
    attr_reader   :source_lists

    # Various further configuration items
    #
    attr_reader   :bytemark_auth_url, :bytemark_calendar_url, :remote_http_timeout, :remote_https_verify_mode, :failed_login_delay
    attr_reader   :max_acknowledgement_time, :working_hours, :dead_zone, :daytime_hours
    attr_reader   :minimal_dns_lookups


    #
    # Set up a base config.
    #
    def initialize
      @server = nil
      @notification_methods = {}
      @people = {}
      @source_lists = Hash.new{|h,k| h[k] = Mauve::SourceList.new(k)}
      @alert_groups = []

      #
      # Set the auth/calendar URLs
      #
      @bytemark_auth_url     = nil
      @bytemark_calendar_url = nil

      #
      # Set a couple of params for remote HTTP requests.
      #
      self.remote_http_timeout = 5
      self.remote_https_verify_mode = "peer"

      #
      # Rate limit login attempts to limit the success of brute-forcing.
      #
      self.failed_login_delay = 1

      #
      # Reduce the amount of DNS lookups when matching alerts to groups.
      #
      self.minimal_dns_lookups = false

      #
      # Maximum amount of time to acknowledge for
      #
      self.max_acknowledgement_time = 15.days

      #
      # Working hours
      #
      self.dead_zone     = 3.0...7.0
      self.daytime_hours = 8.0...22.0
      self.working_hours = 9.5...17.5
    end

    # Set the calendar URL.
    #
    # @param [String] arg
    # @return [URI]
    def bytemark_calendar_url=(arg)
      raise ArgumentError, "bytemark_calendar_url must be a string" unless arg.is_a?(String)

      @bytemark_calendar_url = URI.parse(arg)

      #
      # Make sure we get an HTTP URL.
      #
      raise ArgumentError, "bytemark_calendar_url must be an HTTP(S) URL." unless %w(http https).include?(@bytemark_calendar_url.scheme)

      #
      # Set a default request path, if none was given
      #
      @bytemark_calendar_url.normalize!

      @bytemark_calendar_url
    end

    # Set the Bytemark Authentication URL
    #
    # @param [String] arg
    # @return [URI]
    def bytemark_auth_url=(arg)
      raise ArgumentError, "bytemark_auth_url must be a string" unless arg.is_a?(String)

      @bytemark_auth_url = URI.parse(arg)
      #
      # Make sure we get an HTTP URL.
      #
      raise ArgumentError, "bytemark_auth_url must be an HTTP(S) URL." unless %w(http https).include?(@bytemark_auth_url.scheme)

      #
      # Set a default request path, if none was given
      #
      @bytemark_auth_url.normalize!

      @bytemark_auth_url
    end

    # Sets the timeout when making remote HTTP requests
    #
    # @param [Integer] arg
    # @return [Integer]
    def remote_http_timeout=(arg)
      raise ArgumentError, "remote_http_timeout must be an integer" unless arg.is_a?(Integer)
      @remote_http_timeout = arg
    end

    # Sets the SSL verification mode when makeing remote HTTPS requests
    #
    # @param [String] arg must be one of "none" or "peer"
    # @return [Constant]
    def remote_https_verify_mode=(arg)
      @remote_https_verify_mode = case arg
      when "peer"
        OpenSSL::SSL::VERIFY_PEER
      when "none"
        OpenSSL::SSL::VERIFY_NONE
      else
        raise ArgumentError, "remote_https_verify_mode must be either 'peer' or 'none'"
      end
    end

    # Set the delay added following a failed login attempt.
    #
    # @param [Numeric] arg Number of seconds to delay following a failed login attempt
    # @return [Numeric]
    #
    def failed_login_delay=(arg)
      raise ArgumentError, "failed_login_delay must be numeric" unless arg.is_a?(Numeric)
      @failed_login_delay = arg
    end

    # Set the maximum amount of time alerts can be ack'd for
    #
    #
    def max_acknowledgement_time=(arg)
      raise ArgumentError, "max_acknowledgement_time must be numeric" unless arg.is_a?(Numeric)
      @max_acknowledgement_time = arg
    end

    def calendar=(x)
      lambda{|at| CalendarInterface.get_attendees(x,at)}
    end

    def working_hours=(arg)
      @working_hours = self.class.parse_range(arg)
    end

    def daytime_hours=(arg)
      @daytime_hours = self.class.parse_range(arg)
    end

    def dead_zone=(arg)
      @dead_zone = self.class.parse_range(arg)
    end

    # This method takes a range, and wraps it within the specs defined by
    # allowed_range.
    # 
    # It can take an array of Numerics, Strings, Ranges etc
    #
    # @param 
    #
    def self.parse_range(arg, allowed_range = (0...24))
      args = [arg].flatten

      #
      # Tidy up our allowed ranges
      #
      min = allowed_range.first
      max = allowed_range.last

      #
      # If we've been given a numeric range, make sure they're all floats.
      #
      min = min.to_f if min.is_a?(Numeric)
      max = max.to_f if max.is_a?(Numeric)
      
      ranges = []

      args.each do |arg|
        case arg
          when Range
            from = arg.first
            to = arg.last
            exclude_end = arg.exclude_end?
          else
            from = arg
            to = arg
        end

        from = min unless allowed_range.include?(from)

        #
        # In the case of integers, we want to match up until, but not including
        # the next integer.
        #
        if to.is_a?(Integer)
          to = (exclude_end ? to : to.succ)
          exclude_end = true
        end

        to = max unless allowed_range.include?(to)

        from = from.to_f if from.is_a?(Numeric)
        to   = to.to_f   if to.is_a?(Numeric)

        if from > to or (from >= to and exclude_end)
          ranges << Range.new(from, max, allowed_range.exclude_end?)
          ranges << Range.new(min, to, exclude_end)
        else
          ranges << Range.new(from, to, exclude_end)
        end

      end

      ranges
    end


    def minimal_dns_lookups=(bool)
      if bool.is_a?(TrueClass) or bool.to_s.strip =~ /^(1|y(es)?|t(rue))/
        @minimal_dns_lookups = true
      else
        @minimal_dns_lookups = false
      end
    end

  end


end