rack-devel archive mirror (unofficial) https://groups.google.com/group/rack-devel
 help / color / mirror / code / Atom feed
2f120654ee7f47afef156c855770bb4632ce8ce5 blob 2218 bytes (raw)

 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
 
require "ipaddr"

module Rack

  ##
  # Rack middleware for limiting access based on IP address
  #
  #
  # === Options:
  #
  #   path => ipmasks      ipmasks: Array of remote addresses which are allowed to access
  #
  # === Examples:
  #
  #  use Rack::Access, '/backend' => [ '127.0.0.1',  '192.168.1.0/24' ]
  #
  #

  class Access

    attr_reader :options

    def initialize(app, options = {})
      @app = app
      mapping = options.empty? ? {"/" => ["127.0.0.1"]} : options
      @mapping = remap(mapping)
    end

    def remap(mapping)
      mapping.map { |location, ipmasks|
        if location =~ %r{\Ahttps?://(.*?)(/.*)}
          host, location = $1, $2
        else
          host = nil
        end

        unless location[0] == ?/
          raise ArgumentError, "paths need to start with /"
        end
        location = location.chomp('/')
        match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", nil, 'n')

        ipmasks.collect! do |ipmask|
          ipmask.is_a?(IPAddr) ? ipmask : IPAddr.new(ipmask)
        end
        [host, location, match, ipmasks]
      }.sort_by { |(h, l, m, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] }  # Longest path first
    end

    def call(env)
      @original_request = Request.new(env)
      ipmasks = ipmasks_for_path(env)
      return forbidden! unless ip_authorized?(ipmasks)
      status, headers, body = @app.call(env)
      [status, headers, body]
    end

    def ipmasks_for_path(env)
      path = env["PATH_INFO"].to_s
      hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT')
      @mapping.each do |host, location, match, ipmasks|
        next unless (hHost == host || sName == host \
            || (host.nil? && (hHost == sName || hHost == sName+':'+sPort)))
        next unless path =~ match && rest = $1
        next unless rest.empty? || rest[0] == ?/

        return ipmasks
      end
      nil
    end

    def forbidden!
      [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, '']
    end

    def ip_authorized?(ipmasks)
      return true if ipmasks.nil?

      ipmasks.any? do |ip_mask|
        ip_mask.include?(IPAddr.new(@original_request.ip))
      end
    end

  end
end
debug log:

solving 2f12065 ...
found 2f12065 in https://public-inbox.org/rack-devel/201001150005.30796.pirmin.kalberer@gmail.com/

applying [1/1] https://public-inbox.org/rack-devel/201001150005.30796.pirmin.kalberer@gmail.com/
diff --git a/lib/rack/contrib/access.rb b/lib/rack/contrib/access.rb
new file mode 100644
index 0000000..2f12065

Checking patch lib/rack/contrib/access.rb...
Applied patch lib/rack/contrib/access.rb cleanly.

index at:
100644 2f120654ee7f47afef156c855770bb4632ce8ce5	lib/rack/contrib/access.rb

Code repositories for project(s) associated with this inbox:

	https://80x24.org/mirrors/rack.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).