grempe/rack-json_web_token_auth

View on GitHub
lib/rack/json_web_token_auth/resource.rb

Summary

Maintainability
A
3 hrs
Test Coverage
module Rack
  class JsonWebTokenAuth
    class Resource
      include Contracts::Core
      include Contracts::Builtin

      attr_reader :public_resource, :path, :pattern, :methods, :opts

      Contract Bool, String, ({ jwt: Maybe[Hash], methods: Maybe[ResourceHttpMethods] }) => Any
      def initialize(public_resource, path, opts = {})
        @public_resource = public_resource
        @path = path
        @pattern = compile(path)
        @opts = opts

        if public_resource
          # unsecured resources should not have a :jwt option defined
          if @opts.key?(:jwt)
            raise 'unexpected :jwt option provided for unsecured resource'
          end

          # unsecured resources should not have a :methods option defined
          if @opts.key?(:methods)
            raise 'unexpected :methods option provided for unsecured resource'
          end
        else
          # secured resources must have a :jwt hash with a :key
          unless Contract.valid?(@opts, ({ jwt: { key: nil, alg: 'none' } })) ||
                 Contract.valid?(@opts, ({ jwt: { key: Key } }))
            raise 'invalid or missing jwt options for secured resource'
          end

          # Don't allow providing other HTTP methods with :any
          if opts[:methods] && opts[:methods].include?(:any) && opts[:methods].size > 1
            raise 'unexpected additional methods provided with :any'
          end

          @methods = if opts[:methods].nil?
                       [:get]
                     elsif opts[:methods] == [:any]
                       [:get, :head, :post, :put, :patch, :delete, :options]
                     else
                       opts[:methods]
                     end.map { |e| e.to_s }
        end
      end

      Contract String => Maybe[Integer]
      def matches_path?(path)
        pattern =~ path
      end

      Contract None => Bool
      def public_resource?
        public_resource
      end

      Contract HttpMethods => Bool
      def invalid_http_method?(request_method)
        request_method.nil? || !methods.include?(request_method.downcase)
      end

      protected

      Contract String => Regexp
      def compile(path)
        special_chars = %w{. + ( )}

        pattern = path.gsub(/([\*#{special_chars.join}])/) do |match|
          case match
          when '*'
            '(.*?)'
          when *special_chars
            Regexp.escape(match)
          else
            '([^/?&#]+)'
          end
        end

        /^#{pattern}$/
      end
    end
  end
end