# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/framework/base_support' require 'contrast/framework/sinatra/patch/support' module Contrast module Framework module Sinatra # Used when Sinatra is present to define framework specific behavior class Support < BaseSupport extend Contrast::Framework::Sinatra::Patch::Support class << self def detection_class 'Sinatra' end def version ::Sinatra::VERSION end def application_name return unless app_class app_class.cs__class.cs__name end def application_root return unless app_class app_class.root end def server_type 'sinatra' end # Iterate over every class that extends Sinatra::Base, pull out its routes # (array of arrays with Mustermann::Sinatra as [][0]) and convert them into # Contrast::Api::Dtm::RouteCoverage def collect_routes routes = [] controllers = sinatra_controllers controllers.each do |clazz| class_routes = sinatra_class_routes(clazz) next unless class_routes class_routes.each_pair do |method, list| # item: [ Mustermann::Sinatra, [], Proc] list.each do |item| routes << Contrast::Api::Dtm::RouteCoverage.from_sinatra_route(clazz, method, item[0]) end end end routes end # TODO: RUBY-763 def current_route _request nil end def retrieve_request env ::Sinatra::Request.new(env) end private def app_class return nil unless defined?(::Sinatra) && defined?(::Sinatra::Base) @_app_class ||= begin sinatra_layers = ObjectSpace.each_object(::Sinatra::Base).to_a result_layer = sinatra_layers.find { |layer| layer.app.nil? } result_layer end end # Iterate over every class that extends Sinatra::Base, pull out its routes # (array of arrays with Mustermann::Sinatra as [][0]) and convert them into # Contrast::Api::Dtm::RouteCoverage def sinatra_controllers return [] unless defined?(::Sinatra) && defined?(::Sinatra::Base) Contrast::Utils::ClassUtil.descendants(::Sinatra::Base) end def sinatra_class_routes controller controller.instance_variable_get(:@routes) if controller.instance_variable_defined?(:@routes) rescue StandardError logger.trace('Sinatra controller found with no route instances', module: controller) nil end end end end end end