Module: Belt::Helpers::CorsOrigin

Defined in:
lib/belt/helpers/cors_origin.rb

Constant Summary collapse

MAX_ORIGIN_LENGTH =

Maximum length for an Origin header to prevent ReDoS or memory abuse.

253

Class Method Summary collapse

Class Method Details

.allowed_originsObject



55
56
57
# File 'lib/belt/helpers/cors_origin.rb', line 55

def self.allowed_origins
  @allowed_origins ||= build_allowed_origins
end

.matches_allowed?(origin, allowed) ⇒ Boolean

Returns:

  • (Boolean)


22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/belt/helpers/cors_origin.rb', line 22

def self.matches_allowed?(origin, allowed)
  return false unless origin

  allowed.any? do |pattern|
    if pattern.include?('*')
      regex = Regexp.new("\\A#{Regexp.escape(pattern).gsub('\*', '[a-z0-9\\-]+')}\\z")
      regex.match?(origin)
    else
      pattern == origin
    end
  end
end

.origin_from_event(event) ⇒ Object



46
47
48
49
50
51
52
53
# File 'lib/belt/helpers/cors_origin.rb', line 46

def self.origin_from_event(event)
  return nil unless event.is_a?(Hash)

  headers = event['headers']
  return nil unless headers.is_a?(Hash)

  headers['Origin'] || headers['origin']
end

.reset!Object



59
60
61
# File 'lib/belt/helpers/cors_origin.rb', line 59

def self.reset!
  @allowed_origins = nil
end

.resolve_origin(request_origin) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/belt/helpers/cors_origin.rb', line 9

def self.resolve_origin(request_origin)
  allowed = allowed_origins
  return nil if allowed.empty?

  if request_origin && valid_origin?(request_origin) && matches_allowed?(request_origin, allowed)
    return request_origin
  end

  # Don't return a wildcard pattern as a literal origin — use '*' instead
  first = allowed.first
  first.include?('*') ? '*' : first
end

.valid_origin?(origin) ⇒ Boolean

Validate that the origin looks like a legitimate URL scheme+host. Rejects origins with path components, whitespace, or unexpected characters.

Returns:

  • (Boolean)


37
38
39
40
41
42
43
44
# File 'lib/belt/helpers/cors_origin.rb', line 37

def self.valid_origin?(origin)
  return false if origin.nil? || origin.empty?
  return false if origin.length > MAX_ORIGIN_LENGTH
  return false unless origin.match?(%r{\A https?://[a-z0-9\-.:]+\z}ix)

  # Reject origins with user-info, paths, queries, or fragments
  !origin.include?('@') && !origin.include?('?') && !origin.include?('#')
end