# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/utils/string_utils' module Contrast module Api module Decorators # Used to decorate the {Contrast::Api::Dtm::RouteCoverage} protobuf model # to handle conversion between framework route classes and the dtm. module RouteCoverage def self.included klass klass.extend(ClassMethods) end # Class methods for RouteCoverage module ClassMethods def source_or_string obj if obj.cs__is_a?(Regexp) obj.source elsif obj.cs__respond_to?(:safe_string) obj.safe_string else obj.to_s end end # Convert ActionDispatch::Journey::Route to Contrast::Api::Dtm::RouteCoverage # # @param journey_obj [ActionDispatch::Journey::Route] a rails route # @param url [String, nil] use url from string instead of journey object. # @return [Contrast::Api::Dtm::RouteCoverage] def from_action_dispatch_journey journey_obj, url = nil msg = new msg.route = "#{ journey_obj.defaults[:controller] }##{ journey_obj.defaults[:action] }" verb = source_or_string(journey_obj.verb) msg.verb = Contrast::Utils::StringUtils.force_utf8(verb) url ||= source_or_string(journey_obj.path.spec) msg.url = Contrast::Utils::StringUtils.force_utf8(url) msg end # Convert Sinatra route data to dtm message. # # @param controller [::Sinatra::Base] the route's final controller. # @param method [String] GET, PUT, POST, etc... # @param pattern [::Mustermann::Sinatra] the pattern that was matched in routing. # @param url [String, nil] use url from string instead matched pattern. # @return [Contrast::Api::Dtm::RouteCoverage] def from_sinatra_route controller, method, pattern, url = nil safe_pattern = source_or_string(pattern) safe_url = source_or_string(url || pattern) msg = new msg.route = "#{ controller }##{ method } #{ safe_pattern }" msg.verb = Contrast::Utils::StringUtils.force_utf8(method) msg.url = Contrast::Utils::StringUtils.force_utf8(safe_url) msg end # Convert Grape route data to dtm message. # # @param controller [::Grape::API] the route's final controller. # @param method [String] GET, PUT, POST, etc... # @param url [String, nil] use url from string instead matched pattern. # @param pattern [String, Grape::Router::Route] the pattern that was matched in routing. # @return [Contrast::Api::Dtm::RouteCoverage] def from_grape_controller controller, method, pattern, url = nil if pattern.cs__is_a?(Grape::Router::Route) safe_pattern = pattern.pattern&.path&.to_s safe_url = source_or_string(url || safe_pattern) else safe_pattern = source_or_string(pattern) safe_url = source_or_string(url || pattern) end msg = new msg.route = "#{ controller }##{ method } #{ safe_pattern }" msg.verb = Contrast::Utils::StringUtils.force_utf8(method) msg.url = Contrast::Utils::StringUtils.force_utf8(safe_url) msg end end end end end end Contrast::Api::Dtm::RouteCoverage.include(Contrast::Api::Decorators::RouteCoverage)