# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'fiber' require 'contrast/agent/scope' require 'cs__scope/cs__scope' # This is the Scope component. # # It tracks /Contrast/ scope. That is, "are we currently doing assess or protect stuff within a patched method?" -- # this is how we avoid doing Contrast stuff on Contrast code or creating infinite loops -- or "are we in some other # execution context for which we need to special case?". module Contrast module Components # Constants defined in C: # # MONITOR = Mutex.new This was replaced from Monitor to Mutex. # EXECUTION_CONTEXT = {} Hash containing all of the current ecs as keys pointing to their scope instances. # EC_KEYS = [] set while we get the current ec, and used for sweeping the dead fibers in C. # # Methods defined in C: # # class Interface # initializes the scope for the current fiber context. # def initialize end; # # This returns the scope governing the current execution context. Use this sparingly, preferring the instance # & class methods to access and query scope, rather than interacting with the scope object directly. # def scope_for_current_ec end; # end # # module Scope # Singleton method for cleaning the dead fibers and unused scope instances, scope GC. # def self.sweep_dead_ecs end; # end module Scope # Methods defined in C: # # For each instance method on a scope, define a forwarder to the scope on the # current execution context's scope. # def scope_for_current_ec end; # # all the methods bellow are used as forwarders to be executed in the current ec. # exp: in_contrast_scope? => scope_for_current_ec.enter_contrast_scope! # # Check if we are in contrast scope. # def in_contrast_scope? end; # @return [Boolean] check if we are in contrast scope # if the scope is above 0 return true. # # check if we are in deserialization scope. # def in_deserialization_scope? end; # @return [Boolean] check if we are in contrast scope # if the scope is above 0 return true. # # check if we are in split scope. # def in_split_scope? end; # @return [Boolean] check if we are in contrast scope # if the scope is above 0 return true. # # enter contrast scope. # def enter_contrast_scope! end; # @return @contrast_scope [Integer] contrast scope increased. # # enter deserialization scope. # def enter_deserialization_scope! end; # @return @deserialization_scope [Integer] deserialization scope increased. # # enter split scope. # def enter_split_scope! end; # @return @split_scope [Integer] split scope increased. # # check split scope depth. # def split_scope_depth end; # @return @split_scope [Integer] split scope depth. # # exit contrast scope. # def exit_contrast_scope! end; # @return @contrast_scope [Integer] contrast scope decreased. # # exit deserialization scope. # def exit_deserialization_scope! end; # @return @deserialization_scope [Integer] deserialization scope decreased. # # exit split scope. # def exit_split_scope! end; # @return @split_scope [Integer] split scope decreased. # # Static methods to be used, the cases are defined by the usage from the above methods # # check if are in specific scope. # def in_scope? name end; # @param name [Symbol] scope symbol representing scope to check. # @return [Boolean] check if we are in passed scope. # # enter specific scope. # def enter_scope! name end; # @param name [Symbol] scope symbol representing scope to enter. # @return scope [Integer] entered scope value increased. # # exit specific scope. # def exit_cope! name end; # @param name [Symbol] scope symbol representing scope to exit. # @return scope [Integer] entered scope value decreased. module InstanceMethods # Forwarder to execute block in contrast scope under current # method execution context. On completion exits scope. def with_contrast_scope scope_for_current_ec.enter_contrast_scope! yield ensure scope_for_current_ec.exit_contrast_scope! end # Forwarder to execute block in deserialization scope under current # method execution context. On completion exits scope. def with_deserialization_scope scope_for_current_ec.enter_deserialization_scope! yield ensure scope_for_current_ec.exit_deserialization_scope! end # Forwarder to execute block in split scope under current # method execution context. On completion exits scope. def with_split_scope scope_for_current_ec.enter_split_scope! yield ensure scope_for_current_ec.exit_split_scope! end # Enter app scope def with_app_scope scope_for_current_ec.exit_contrast_scope! yield ensure scope_for_current_ec.enter_contrast_scope! end end ClassMethods = InstanceMethods end end end